[EXPERIMENTAL] Add Rust support
This commit is contained in:
parent
68adb14b07
commit
f4dcd55f98
|
@ -11,6 +11,9 @@ jobs:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
|
||||||
- name: Checkout the code
|
- name: Checkout the code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -15,6 +15,9 @@ jobs:
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
|
||||||
- name: Checkout the code
|
- name: Checkout the code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -10,6 +10,9 @@ jobs:
|
||||||
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
|
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
|
||||||
- name: Checkout the code
|
- name: Checkout the code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -12,6 +12,9 @@ jobs:
|
||||||
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
|
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
|
||||||
- name: Checkout the code
|
- name: Checkout the code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -17,3 +17,7 @@ compile_commands.json
|
||||||
|
|
||||||
# mac finder crap
|
# mac finder crap
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
|
||||||
|
# Rust build files
|
||||||
|
src/core/rust/target/
|
||||||
|
src/core/rust/Cargo.lock
|
||||||
|
|
|
@ -74,6 +74,15 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED True)
|
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
# Rust library dependency
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
Corrosion
|
||||||
|
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
||||||
|
GIT_TAG v0.4
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(Corrosion)
|
||||||
|
|
||||||
project(VBA-M C CXX)
|
project(VBA-M C CXX)
|
||||||
|
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
|
@ -263,15 +272,6 @@ add_compile_definitions(PKGDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/vbam")
|
||||||
add_compile_definitions(__STDC_FORMAT_MACROS)
|
add_compile_definitions(__STDC_FORMAT_MACROS)
|
||||||
|
|
||||||
if(ENABLE_LINK)
|
if(ENABLE_LINK)
|
||||||
# IPC linking code needs sem_timedwait which can be either in librt or pthreads
|
|
||||||
if(NOT WIN32)
|
|
||||||
find_library(RT_LIB rt)
|
|
||||||
if(RT_LIB)
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${RT_LIB})
|
|
||||||
set(VBAMCORE_LIBS ${VBAMCORE_LIBS} ${RT_LIB})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(CheckFunctionExists)
|
include(CheckFunctionExists)
|
||||||
check_function_exists(sem_timedwait SEM_TIMEDWAIT)
|
check_function_exists(sem_timedwait SEM_TIMEDWAIT)
|
||||||
if(SEM_TIMEDWAIT)
|
if(SEM_TIMEDWAIT)
|
||||||
|
|
|
@ -218,7 +218,6 @@ Here is the complete list:
|
||||||
| ENABLE_GBA_LOGGING | Enable extended GBA logging | ON |
|
| ENABLE_GBA_LOGGING | Enable extended GBA logging | ON |
|
||||||
| ENABLE_DIRECT3D | Direct3D rendering for wxWidgets (Windows, **NOT IMPLEMENTED!!!**) | ON |
|
| ENABLE_DIRECT3D | Direct3D rendering for wxWidgets (Windows, **NOT IMPLEMENTED!!!**) | ON |
|
||||||
| ENABLE_XAUDIO2 | Enable xaudio2 sound output for wxWidgets (Windows only) | ON |
|
| ENABLE_XAUDIO2 | Enable xaudio2 sound output for wxWidgets (Windows only) | ON |
|
||||||
| ENABLE_OPENAL | Enable OpenAL for the wxWidgets port | AUTO |
|
|
||||||
| ENABLE_ASAN | Enable libasan sanitizers (by default address, only in debug mode) | OFF |
|
| ENABLE_ASAN | Enable libasan sanitizers (by default address, only in debug mode) | OFF |
|
||||||
| UPSTREAM_RELEASE | Do some release tasks, like codesigning, making zip and gpg sigs. | OFF |
|
| UPSTREAM_RELEASE | Do some release tasks, like codesigning, making zip and gpg sigs. | OFF |
|
||||||
| BUILD_TESTING | Build the tests and enable ctest support. | ON |
|
| BUILD_TESTING | Build the tests and enable ctest support. | ON |
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Compiler stuff
|
||||||
|
include(ProcessorCount)
|
||||||
|
ProcessorCount(num_cpus)
|
||||||
|
|
||||||
|
if(CMAKE_C_COMPILER_ID STREQUAL Clang AND CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT MSVC)
|
||||||
|
# TODO: This should also be done for clang-cl.
|
||||||
|
include(LLVMToolchain)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT MSVC)
|
||||||
|
include(Toolchain-gcc-clang)
|
||||||
|
elseif(MSVC)
|
||||||
|
include(Toolchain-msvc)
|
||||||
|
elseif(MINGW)
|
||||||
|
include(Toolchain-mingw)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Assembler flags
|
||||||
|
if(ASM_ENABLED)
|
||||||
|
string(REGEX REPLACE "<FLAGS>" "-I${CMAKE_SOURCE_DIR}/src/filters/hq/asm/ -O1 -w-orphan-labels" CMAKE_ASM_NASM_COMPILE_OBJECT ${CMAKE_ASM_NASM_COMPILE_OBJECT})
|
||||||
|
endif()
|
|
@ -0,0 +1,44 @@
|
||||||
|
#Do not use this file directly. Always use the top level CMakeLists.txt file
|
||||||
|
#File extractors so the user doesn't have to extract the rom before playing it
|
||||||
|
|
||||||
|
# Source files definition
|
||||||
|
SET(SRC_FEX
|
||||||
|
7z_C/7zAlloc.c
|
||||||
|
7z_C/7zBuf.c
|
||||||
|
7z_C/7zCrc.c
|
||||||
|
7z_C/7zCrcOpt.c
|
||||||
|
7z_C/7zDec.c
|
||||||
|
7z_C/7zIn.c
|
||||||
|
7z_C/7zStream.c
|
||||||
|
7z_C/Bcj2.c
|
||||||
|
7z_C/Bra86.c
|
||||||
|
7z_C/Bra.c
|
||||||
|
7z_C/CpuArch.c
|
||||||
|
7z_C/Lzma2Dec.c
|
||||||
|
7z_C/LzmaDec.c
|
||||||
|
7z_C/Ppmd7.c
|
||||||
|
7z_C/Ppmd7Dec.c
|
||||||
|
fex/Binary_Extractor.cpp
|
||||||
|
fex/blargg_common.cpp
|
||||||
|
fex/blargg_errors.cpp
|
||||||
|
fex/Data_Reader.cpp
|
||||||
|
fex/fex.cpp
|
||||||
|
fex/File_Extractor.cpp
|
||||||
|
fex/Gzip_Extractor.cpp
|
||||||
|
fex/Gzip_Reader.cpp
|
||||||
|
fex/Rar_Extractor.cpp
|
||||||
|
fex/Zip7_Extractor.cpp
|
||||||
|
fex/Zip_Extractor.cpp
|
||||||
|
fex/Zlib_Inflater.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_LIBRARY(
|
||||||
|
fex
|
||||||
|
STATIC
|
||||||
|
${SRC_FEX}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(fex generate)
|
||||||
|
|
||||||
|
target_include_directories(fex PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
target_link_libraries(fex PUBLIC ZLIB::ZLIB)
|
54
installdeps
54
installdeps
|
@ -1,7 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
CMAKE=cmake
|
CMAKE=cmake
|
||||||
ENABLE_OPENAL=1
|
|
||||||
ENABLE_FFMPEG=1
|
ENABLE_FFMPEG=1
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
@ -25,10 +24,6 @@ check_command_line_args() {
|
||||||
usage
|
usage
|
||||||
quit 0
|
quit 0
|
||||||
;;
|
;;
|
||||||
--no-openal)
|
|
||||||
ENABLE_OPENAL=
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--no-ffmpeg)
|
--no-ffmpeg)
|
||||||
ENABLE_FFMPEG=
|
ENABLE_FFMPEG=
|
||||||
shift
|
shift
|
||||||
|
@ -355,9 +350,8 @@ debian_installdeps() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl2-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev libsfml-dev $sfml_libs $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build"
|
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl2-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev libsfml-dev $sfml_libs $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build libopenal-dev"
|
||||||
|
|
||||||
[ -n "$ENABLE_OPENAL" ] && pkgs="$pkgs libopenal-dev"
|
|
||||||
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev"
|
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev"
|
||||||
|
|
||||||
check sudo apt-get -qy install $pkgs
|
check sudo apt-get -qy install $pkgs
|
||||||
|
@ -407,8 +401,7 @@ debian_installdeps() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
deps="gcc zlib ffmpeg gettext sdl2 sfml openal wxwidgets"
|
deps="gcc zlib ffmpeg gettext sdl2 sfml openal wxwidgets openal"
|
||||||
[ -n "$ENABLE_OPENAL" ] && deps="$deps openal"
|
|
||||||
[ -n "$ENABLE_FFMPEG" ] && deps="$deps ffmpeg"
|
[ -n "$ENABLE_FFMPEG" ] && deps="$deps ffmpeg"
|
||||||
|
|
||||||
set --
|
set --
|
||||||
|
@ -510,9 +503,6 @@ fedora_installdeps() {
|
||||||
*ffmpeg*)
|
*ffmpeg*)
|
||||||
[ -z "$ENABLE_FFMPEG" ] && continue
|
[ -z "$ENABLE_FFMPEG" ] && continue
|
||||||
;;
|
;;
|
||||||
*openal*)
|
|
||||||
[ -z "$ENABLE_OPENAL" ] && continue
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
pkg_arch=
|
pkg_arch=
|
||||||
|
@ -601,15 +591,9 @@ fedora_installdeps() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
# install static deps
|
# install static deps
|
||||||
for pkg in zlib gettext SDL2 wxWidgets3; do
|
for pkg in zlib gettext SDL2 wxWidgets3 openal-soft; do
|
||||||
set -- "$@" "${target}-${pkg}-static"
|
set -- "$@" "${target}-${pkg}-static"
|
||||||
done
|
done
|
||||||
# install deps that are not available as static
|
|
||||||
if [ -n "$ENABLE_OPENAL" ]; then
|
|
||||||
for pkg in openal-soft; do
|
|
||||||
set -- "$@" "${target}-${pkg}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# get the necessary win32 headers
|
# get the necessary win32 headers
|
||||||
git submodule update --init --remote --recursive
|
git submodule update --init --remote --recursive
|
||||||
|
@ -707,9 +691,6 @@ rhel_installdeps() {
|
||||||
*ffmpeg*)
|
*ffmpeg*)
|
||||||
[ -z "$ENABLE_FFMPEG" ] && continue
|
[ -z "$ENABLE_FFMPEG" ] && continue
|
||||||
;;
|
;;
|
||||||
*openal*)
|
|
||||||
[ -z "$ENABLE_OPENAL" ] && continue
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ -n "$amd64" ]; then
|
if [ -n "$amd64" ]; then
|
||||||
|
@ -790,15 +771,9 @@ rhel_installdeps() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
# install static deps
|
# install static deps
|
||||||
for pkg in zlib gettext SDL2 wxWidgets; do
|
for pkg in zlib gettext SDL2 wxWidgets openal-soft; do
|
||||||
set -- "$@" "${target}-${pkg}-static"
|
set -- "$@" "${target}-${pkg}-static"
|
||||||
done
|
done
|
||||||
# install deps that are not available as static
|
|
||||||
if [ -n "$ENABLE_OPENAL" ]; then
|
|
||||||
for pkg in openal-soft; do
|
|
||||||
set -- "$@" "${target}-${pkg}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# get the necessary win32 headers
|
# get the necessary win32 headers
|
||||||
git submodule update --init --remote --recursive
|
git submodule update --init --remote --recursive
|
||||||
|
@ -824,11 +799,9 @@ suse_installdeps() {
|
||||||
|
|
||||||
tools="make cmake ccache nasm gettext-tools pkg-config ccache zip sfml2-devel ninja"
|
tools="make cmake ccache nasm gettext-tools pkg-config ccache zip sfml2-devel ninja"
|
||||||
|
|
||||||
libs="gcc gcc-c++ libSDL2-devel wxWidgets-3_0-devel" # ffmpeg-devel
|
libs="gcc gcc-c++ libSDL2-devel wxWidgets-3_0-devel openal-soft-devel" # ffmpeg-devel
|
||||||
|
|
||||||
[ -n "$ENABLE_OPENAL" ] && libs="$libs openal-soft-devel"
|
|
||||||
# ffmpeg requires packman repos
|
# ffmpeg requires packman repos
|
||||||
|
|
||||||
if [ "$target" = m32 ]; then
|
if [ "$target" = m32 ]; then
|
||||||
libs=$(echo "$libs" | sed -E 's/([^ ]) ([^ ])/\1-32bit \2/g; s/$/-32bit/;')
|
libs=$(echo "$libs" | sed -E 's/([^ ]) ([^ ])/\1-32bit \2/g; s/$/-32bit/;')
|
||||||
fi
|
fi
|
||||||
|
@ -894,9 +867,8 @@ archlinux_installdeps() {
|
||||||
|
|
||||||
$pacman -Q gtk3-classic >/dev/null 2>&1 && gtk=gtk3-classic
|
$pacman -Q gtk3-classic >/dev/null 2>&1 && gtk=gtk3-classic
|
||||||
|
|
||||||
libs="zlib mesa gettext sdl2 wxgtk3 $gtk sfml"
|
libs="zlib mesa gettext sdl2 wxgtk3 $gtk sfml openal"
|
||||||
|
|
||||||
[ -n "$ENABLE_OPENAL" ] && libs="$libs openal"
|
|
||||||
[ -n "$ENABLE_FFMPEG" ] && libs="$libs ffmpeg"
|
[ -n "$ENABLE_FFMPEG" ] && libs="$libs ffmpeg"
|
||||||
|
|
||||||
if [ -z "$target" -o "$target" = m32 ]; then
|
if [ -z "$target" -o "$target" = m32 ]; then
|
||||||
|
@ -991,9 +963,7 @@ EOF
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
deps="zlib gettext pkg-config sdl2 wxmsw"
|
deps="zlib gettext pkg-config sdl2 wxmsw openal"
|
||||||
|
|
||||||
[ -n "$ENABLE_OPENAL" ] && deps="$deps openal"
|
|
||||||
|
|
||||||
# and the actual deps
|
# and the actual deps
|
||||||
for p in $deps; do
|
for p in $deps; do
|
||||||
|
@ -1024,9 +994,7 @@ solus_installdeps() {
|
||||||
check sudo eopkg -y install -c system.devel
|
check sudo eopkg -y install -c system.devel
|
||||||
check sudo eopkg -y install git ccache ninja
|
check sudo eopkg -y install git ccache ninja
|
||||||
|
|
||||||
set -- sdl2-devel wxwidgets-devel libgtk-2-devel libgtk-3-devel libglu-devel
|
set -- sdl2-devel wxwidgets-devel libgtk-2-devel libgtk-3-devel libglu-devel openal-soft-devel
|
||||||
|
|
||||||
[ -n "$ENABLE_OPENAL" ] && set -- "$@" openal-soft-devel
|
|
||||||
|
|
||||||
if [ -n "$amd64" -a "$target" = m32 ]; then
|
if [ -n "$amd64" -a "$target" = m32 ]; then
|
||||||
info_msg 'Calculating dependencies, this will take a while..'
|
info_msg 'Calculating dependencies, this will take a while..'
|
||||||
|
@ -1102,14 +1070,13 @@ gentoo_installdeps() {
|
||||||
sys-devel/binutils \
|
sys-devel/binutils \
|
||||||
media-libs/libsdl2 \
|
media-libs/libsdl2 \
|
||||||
media-libs/libsfml \
|
media-libs/libsfml \
|
||||||
|
media-libs/openal \
|
||||||
x11-libs/wxGTK:$wx_slot \
|
x11-libs/wxGTK:$wx_slot \
|
||||||
sys-libs/zlib \
|
sys-libs/zlib \
|
||||||
dev-util/pkgconf \
|
dev-util/pkgconf \
|
||||||
dev-lang/nasm \
|
dev-lang/nasm \
|
||||||
dev-build/ninja"
|
dev-build/ninja"
|
||||||
|
|
||||||
[ -n "$ENABLE_OPENAL" ] && ebuilds="$ebuilds media-libs/openal"
|
|
||||||
|
|
||||||
[ -n "$ENABLE_FFMPEG" ] && ebuilds="$ebuilds media-video/ffmpeg"
|
[ -n "$ENABLE_FFMPEG" ] && ebuilds="$ebuilds media-video/ffmpeg"
|
||||||
|
|
||||||
check sudo emerge -vna $ebuilds
|
check sudo emerge -vna $ebuilds
|
||||||
|
@ -1152,9 +1119,8 @@ windows_installdeps() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
pkgs="$pkgs SDL2 sfml wxWidgets3.2 zlib binutils cmake crt-git extra-cmake-modules headers-git make pkgconf tools-git windows-default-manifest libmangle-git ninja gdb ccache"
|
pkgs="$pkgs SDL2 sfml wxWidgets3.2 zlib binutils cmake crt-git extra-cmake-modules headers-git make pkgconf tools-git windows-default-manifest libmangle-git ninja gdb ccache openal"
|
||||||
|
|
||||||
[ -n "$ENABLE_OPENAL" ] && pkgs="$pkgs openal"
|
|
||||||
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs ffmpeg"
|
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs ffmpeg"
|
||||||
|
|
||||||
set --
|
set --
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "stable"
|
||||||
|
profile = "minimal"
|
|
@ -51,7 +51,6 @@ parts:
|
||||||
- libopenal-dev
|
- libopenal-dev
|
||||||
- libwxgtk3.0-gtk3-dev
|
- libwxgtk3.0-gtk3-dev
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
- -DENABLE_OPENAL=ON
|
|
||||||
- -DENABLE_SDL=OFF
|
- -DENABLE_SDL=OFF
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ add_subdirectory(apu)
|
||||||
add_subdirectory(base)
|
add_subdirectory(base)
|
||||||
add_subdirectory(fex)
|
add_subdirectory(fex)
|
||||||
|
|
||||||
|
# Set up "vbam_rust" library.
|
||||||
|
corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_LIST_DIR}/rust/Cargo.toml NO_STD)
|
||||||
|
|
||||||
# The vbam-core target contains both the Game Boy and Game Boy Advance
|
# The vbam-core target contains both the Game Boy and Game Boy Advance
|
||||||
# emulators. These should be broken down into 2 separate targets. The issue lies
|
# emulators. These should be broken down into 2 separate targets. The issue lies
|
||||||
# with the Link and Sound emulation, which are tangled together between the two
|
# with the Link and Sound emulation, which are tangled together between the two
|
||||||
|
@ -94,7 +97,7 @@ target_include_directories(vbam-core
|
||||||
|
|
||||||
target_link_libraries(vbam-core
|
target_link_libraries(vbam-core
|
||||||
PRIVATE vbam-core-apu vbam-fex
|
PRIVATE vbam-core-apu vbam-fex
|
||||||
PUBLIC vbam-core-base ${ZLIB_LIBRARY}
|
PUBLIC vbam-core-base ${ZLIB_LIBRARY} vbam_rust
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_DEBUGGER)
|
if(ENABLE_DEBUGGER)
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
#include "core/base/file_util.h"
|
#include "core/base/file_util.h"
|
||||||
#include "core/base/message.h"
|
#include "core/base/message.h"
|
||||||
#include "core/gba/gba.h"
|
#include "core/gba/gba.h"
|
||||||
#include "core/gba/gbaInline.h"
|
|
||||||
#include "core/gba/gbaGlobals.h"
|
#include "core/gba/gbaGlobals.h"
|
||||||
|
#include "core/gba/gbaInline.h"
|
||||||
|
#include "core/rust/bindings.hpp"
|
||||||
|
|
||||||
|
using namespace core;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gameshark code types: (based on AR v1.0)
|
* Gameshark code types: (based on AR v1.0)
|
||||||
|
@ -672,7 +675,7 @@ int cheatsCheckKeys(uint32_t keys, uint32_t extended)
|
||||||
case GSA_16_BIT_ROM_PATCH:
|
case GSA_16_BIT_ROM_PATCH:
|
||||||
if ((cheatsList[i].status & 1) == 0) {
|
if ((cheatsList[i].status & 1) == 0) {
|
||||||
if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) {
|
if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) {
|
||||||
cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address);
|
cheatsList[i].old_value = CPUReadHalfWord(cheatsList[i].address);
|
||||||
cheatsList[i].status |= 1;
|
cheatsList[i].status |= 1;
|
||||||
CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value);
|
CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value);
|
||||||
}
|
}
|
||||||
|
@ -1280,6 +1283,33 @@ int cheatsCheckKeys(uint32_t keys, uint32_t extended)
|
||||||
return ticks;
|
return ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cheatsAdd(CheatsData data) {
|
||||||
|
if (cheatsNumber == MAX_CHEATS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = cheatsNumber;
|
||||||
|
cheatsList[x] = std::move(data);
|
||||||
|
switch (cheatsList[x].size) {
|
||||||
|
case INT_8_BIT_WRITE:
|
||||||
|
cheatsList[x].old_value = CPUReadByte(cheatsList[x].address);
|
||||||
|
break;
|
||||||
|
case INT_16_BIT_WRITE:
|
||||||
|
cheatsList[x].old_value = CPUReadHalfWord(cheatsList[x].address);
|
||||||
|
break;
|
||||||
|
case INT_32_BIT_WRITE:
|
||||||
|
cheatsList[x].old_value = CPUReadMemory(cheatsList[x].address);
|
||||||
|
break;
|
||||||
|
case CHEATS_16_BIT_WRITE:
|
||||||
|
cheatsList[x].old_value = CPUReadHalfWord(cheatsList[x].address);
|
||||||
|
break;
|
||||||
|
case CHEATS_32_BIT_WRITE:
|
||||||
|
cheatsList[x].old_value = CPUReadMemory(cheatsList[x].address);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cheatsNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
void cheatsAdd(const char* codeStr,
|
void cheatsAdd(const char* codeStr,
|
||||||
const char* desc,
|
const char* desc,
|
||||||
uint32_t rawaddress,
|
uint32_t rawaddress,
|
||||||
|
@ -1304,19 +1334,19 @@ void cheatsAdd(const char* codeStr,
|
||||||
// is taken care when it actually patches the ROM
|
// is taken care when it actually patches the ROM
|
||||||
switch (cheatsList[x].size) {
|
switch (cheatsList[x].size) {
|
||||||
case INT_8_BIT_WRITE:
|
case INT_8_BIT_WRITE:
|
||||||
cheatsList[x].oldValue = CPUReadByte(address);
|
cheatsList[x].old_value = CPUReadByte(address);
|
||||||
break;
|
break;
|
||||||
case INT_16_BIT_WRITE:
|
case INT_16_BIT_WRITE:
|
||||||
cheatsList[x].oldValue = CPUReadHalfWord(address);
|
cheatsList[x].old_value = CPUReadHalfWord(address);
|
||||||
break;
|
break;
|
||||||
case INT_32_BIT_WRITE:
|
case INT_32_BIT_WRITE:
|
||||||
cheatsList[x].oldValue = CPUReadMemory(address);
|
cheatsList[x].old_value = CPUReadMemory(address);
|
||||||
break;
|
break;
|
||||||
case CHEATS_16_BIT_WRITE:
|
case CHEATS_16_BIT_WRITE:
|
||||||
cheatsList[x].oldValue = CPUReadHalfWord(address);
|
cheatsList[x].old_value = CPUReadHalfWord(address);
|
||||||
break;
|
break;
|
||||||
case CHEATS_32_BIT_WRITE:
|
case CHEATS_32_BIT_WRITE:
|
||||||
cheatsList[x].oldValue = CPUReadMemory(address);
|
cheatsList[x].old_value = CPUReadMemory(address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cheatsNumber++;
|
cheatsNumber++;
|
||||||
|
@ -1331,33 +1361,33 @@ void cheatsDelete(int number, bool restore)
|
||||||
if (restore) {
|
if (restore) {
|
||||||
switch (cheatsList[x].size) {
|
switch (cheatsList[x].size) {
|
||||||
case INT_8_BIT_WRITE:
|
case INT_8_BIT_WRITE:
|
||||||
CPUWriteByte(cheatsList[x].address, (uint8_t)cheatsList[x].oldValue);
|
CPUWriteByte(cheatsList[x].address, (uint8_t)cheatsList[x].old_value);
|
||||||
break;
|
break;
|
||||||
case INT_16_BIT_WRITE:
|
case INT_16_BIT_WRITE:
|
||||||
CPUWriteHalfWord(cheatsList[x].address, (uint16_t)cheatsList[x].oldValue);
|
CPUWriteHalfWord(cheatsList[x].address, (uint16_t)cheatsList[x].old_value);
|
||||||
break;
|
break;
|
||||||
case INT_32_BIT_WRITE:
|
case INT_32_BIT_WRITE:
|
||||||
CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue);
|
CPUWriteMemory(cheatsList[x].address, cheatsList[x].old_value);
|
||||||
break;
|
break;
|
||||||
case CHEATS_16_BIT_WRITE:
|
case CHEATS_16_BIT_WRITE:
|
||||||
if ((cheatsList[x].address >> 24) >= 0x08) {
|
if ((cheatsList[x].address >> 24) >= 0x08) {
|
||||||
CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, cheatsList[x].oldValue);
|
CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, cheatsList[x].old_value);
|
||||||
} else {
|
} else {
|
||||||
CPUWriteHalfWord(cheatsList[x].address, cheatsList[x].oldValue);
|
CPUWriteHalfWord(cheatsList[x].address, cheatsList[x].old_value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CHEATS_32_BIT_WRITE:
|
case CHEATS_32_BIT_WRITE:
|
||||||
if ((cheatsList[x].address >> 24) >= 0x08) {
|
if ((cheatsList[x].address >> 24) >= 0x08) {
|
||||||
CHEAT_PATCH_ROM_32BIT(cheatsList[x].address, cheatsList[x].oldValue);
|
CHEAT_PATCH_ROM_32BIT(cheatsList[x].address, cheatsList[x].old_value);
|
||||||
} else {
|
} else {
|
||||||
CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue);
|
CPUWriteMemory(cheatsList[x].address, cheatsList[x].old_value);
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case GSA_16_BIT_ROM_PATCH:
|
case GSA_16_BIT_ROM_PATCH:
|
||||||
if (cheatsList[x].status & 1) {
|
if (cheatsList[x].status & 1) {
|
||||||
cheatsList[x].status &= ~1;
|
cheatsList[x].status &= ~1;
|
||||||
CHEAT_PATCH_ROM_16BIT(cheatsList[x].address,
|
CHEAT_PATCH_ROM_16BIT(cheatsList[x].address,
|
||||||
cheatsList[x].oldValue);
|
cheatsList[x].old_value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GSA_16_BIT_ROM_PATCH2C:
|
case GSA_16_BIT_ROM_PATCH2C:
|
||||||
|
@ -1403,7 +1433,7 @@ void cheatsDisable(int i)
|
||||||
if (cheatsList[i].status & 1) {
|
if (cheatsList[i].status & 1) {
|
||||||
cheatsList[i].status &= ~1;
|
cheatsList[i].status &= ~1;
|
||||||
CHEAT_PATCH_ROM_16BIT(cheatsList[i].address,
|
CHEAT_PATCH_ROM_16BIT(cheatsList[i].address,
|
||||||
cheatsList[i].oldValue);
|
cheatsList[i].old_value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GSA_16_BIT_ROM_PATCH2C:
|
case GSA_16_BIT_ROM_PATCH2C:
|
||||||
|
@ -1424,72 +1454,15 @@ void cheatsDisable(int i)
|
||||||
|
|
||||||
bool cheatsVerifyCheatCode(const char* code, const char* desc)
|
bool cheatsVerifyCheatCode(const char* code, const char* desc)
|
||||||
{
|
{
|
||||||
size_t len = strlen(code);
|
auto converted = core::decode_code(core::GbaCheatsType::Generic, code, desc);
|
||||||
if (len != 11 && len != 13 && len != 17) {
|
if (converted.tag ==
|
||||||
systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': wrong length"), code);
|
core::Result_CheatsData__CheatsDecodeError_Tag::Err_CheatsData__CheatsDecodeError) {
|
||||||
|
systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': %s"), code,
|
||||||
|
converted.err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code[8] != ':') {
|
cheatsAdd(std::move(converted.ok));
|
||||||
systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': no colon"), code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
if (!CHEAT_IS_HEX(code[i])) {
|
|
||||||
// wrong cheat
|
|
||||||
systemMessage(MSG_INVALID_CHEAT_CODE,
|
|
||||||
N_("Invalid cheat code '%s': first part is not hex"), code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 9; i < len; i++) {
|
|
||||||
if (!CHEAT_IS_HEX(code[i])) {
|
|
||||||
// wrong cheat
|
|
||||||
systemMessage(MSG_INVALID_CHEAT_CODE,
|
|
||||||
N_("Invalid cheat code '%s' second part is not hex"), code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t address = 0;
|
|
||||||
uint32_t value = 0;
|
|
||||||
|
|
||||||
char buffer[10];
|
|
||||||
strncpy(buffer, code, 8);
|
|
||||||
buffer[8] = 0;
|
|
||||||
sscanf(buffer, "%x", &address);
|
|
||||||
|
|
||||||
switch (address >> 24) {
|
|
||||||
case 0x02:
|
|
||||||
case 0x03:
|
|
||||||
case 0x04:
|
|
||||||
case 0x05:
|
|
||||||
case 0x06:
|
|
||||||
case 0x07:
|
|
||||||
case 0x08:
|
|
||||||
case 0x09:
|
|
||||||
case 0x0A:
|
|
||||||
case 0x0B:
|
|
||||||
case 0x0C:
|
|
||||||
case 0x0D:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS,
|
|
||||||
N_("Invalid cheat code address: %08x"),
|
|
||||||
address);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(buffer, &code[9], 8);
|
|
||||||
sscanf(buffer, "%x", &value);
|
|
||||||
int type = 0;
|
|
||||||
if (len == 13)
|
|
||||||
type = 114;
|
|
||||||
if (len == 17)
|
|
||||||
type = 115;
|
|
||||||
cheatsAdd(code, desc, address, address, value, type, type);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2606,7 +2579,7 @@ void cheatsReadGame(gzFile file, int version)
|
||||||
utilGzRead(file, &cheatsList[i].address, sizeof(uint32_t));
|
utilGzRead(file, &cheatsList[i].address, sizeof(uint32_t));
|
||||||
cheatsList[i].rawaddress = cheatsList[i].address;
|
cheatsList[i].rawaddress = cheatsList[i].address;
|
||||||
utilGzRead(file, &cheatsList[i].value, sizeof(uint32_t));
|
utilGzRead(file, &cheatsList[i].value, sizeof(uint32_t));
|
||||||
utilGzRead(file, &cheatsList[i].oldValue, sizeof(uint32_t));
|
utilGzRead(file, &cheatsList[i].old_value, sizeof(uint32_t));
|
||||||
utilGzRead(file, &cheatsList[i].codestring, 20 * sizeof(char));
|
utilGzRead(file, &cheatsList[i].codestring, 20 * sizeof(char));
|
||||||
utilGzRead(file, &cheatsList[i].desc, 32 * sizeof(char));
|
utilGzRead(file, &cheatsList[i].desc, 32 * sizeof(char));
|
||||||
}
|
}
|
||||||
|
@ -2743,7 +2716,7 @@ bool cheatsLoadCheatList(const char* file)
|
||||||
FREAD_UNCHECKED(&cheatsList[i].address, 1, sizeof(uint32_t), f);
|
FREAD_UNCHECKED(&cheatsList[i].address, 1, sizeof(uint32_t), f);
|
||||||
cheatsList[i].rawaddress = cheatsList[i].address;
|
cheatsList[i].rawaddress = cheatsList[i].address;
|
||||||
FREAD_UNCHECKED(&cheatsList[i].value, 1, sizeof(uint32_t), f);
|
FREAD_UNCHECKED(&cheatsList[i].value, 1, sizeof(uint32_t), f);
|
||||||
FREAD_UNCHECKED(&cheatsList[i].oldValue, 1, sizeof(uint32_t), f);
|
FREAD_UNCHECKED(&cheatsList[i].old_value, 1, sizeof(uint32_t), f);
|
||||||
FREAD_UNCHECKED(&cheatsList[i].codestring, 1, 20 * sizeof(char), f);
|
FREAD_UNCHECKED(&cheatsList[i].codestring, 1, 20 * sizeof(char), f);
|
||||||
if (fread(&cheatsList[i].desc, 1, 32 * sizeof(char), f) != 32 * sizeof(char)) {
|
if (fread(&cheatsList[i].desc, 1, 32 * sizeof(char), f) != 32 * sizeof(char)) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
@ -2829,9 +2802,9 @@ void cheatsWriteMemory(uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
if (cheatsNumber == 0) {
|
if (cheatsNumber == 0) {
|
||||||
int type = cheatsGetType(address);
|
int type = cheatsGetType(address);
|
||||||
uint32_t oldValue = debuggerReadMemory(address);
|
uint32_t old_value = debuggerReadMemory(address);
|
||||||
if (type == 1 || (type == 2 && oldValue != value)) {
|
if (type == 1 || (type == 2 && old_value != value)) {
|
||||||
debuggerBreakOnWrite(address, oldValue, value, 2, type);
|
debuggerBreakOnWrite(address, old_value, value, 2, type);
|
||||||
cpuNextEvent = 0;
|
cpuNextEvent = 0;
|
||||||
}
|
}
|
||||||
debuggerWriteMemory(address, value);
|
debuggerWriteMemory(address, value);
|
||||||
|
@ -2842,9 +2815,9 @@ void cheatsWriteHalfWord(uint32_t address, uint16_t value)
|
||||||
{
|
{
|
||||||
if (cheatsNumber == 0) {
|
if (cheatsNumber == 0) {
|
||||||
int type = cheatsGetType(address);
|
int type = cheatsGetType(address);
|
||||||
uint16_t oldValue = debuggerReadHalfWord(address);
|
uint16_t old_value = debuggerReadHalfWord(address);
|
||||||
if (type == 1 || (type == 2 && oldValue != value)) {
|
if (type == 1 || (type == 2 && old_value != value)) {
|
||||||
debuggerBreakOnWrite(address, oldValue, value, 1, type);
|
debuggerBreakOnWrite(address, old_value, value, 1, type);
|
||||||
cpuNextEvent = 0;
|
cpuNextEvent = 0;
|
||||||
}
|
}
|
||||||
debuggerWriteHalfWord(address, value);
|
debuggerWriteHalfWord(address, value);
|
||||||
|
@ -2855,9 +2828,9 @@ void cheatsWriteByte(uint32_t address, uint8_t value)
|
||||||
{
|
{
|
||||||
if (cheatsNumber == 0) {
|
if (cheatsNumber == 0) {
|
||||||
int type = cheatsGetType(address);
|
int type = cheatsGetType(address);
|
||||||
uint8_t oldValue = debuggerReadByte(address);
|
uint8_t old_value = debuggerReadByte(address);
|
||||||
if (type == 1 || (type == 2 && oldValue != value)) {
|
if (type == 1 || (type == 2 && old_value != value)) {
|
||||||
debuggerBreakOnWrite(address, oldValue, value, 0, type);
|
debuggerBreakOnWrite(address, old_value, value, 0, type);
|
||||||
cpuNextEvent = 0;
|
cpuNextEvent = 0;
|
||||||
}
|
}
|
||||||
debuggerWriteByte(address, value);
|
debuggerWriteByte(address, value);
|
||||||
|
|
|
@ -9,18 +9,7 @@
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#endif // defined(__LIBRETRO__)
|
#endif // defined(__LIBRETRO__)
|
||||||
|
|
||||||
struct CheatsData {
|
#include "core/rust/bindings.hpp"
|
||||||
int code;
|
|
||||||
int size;
|
|
||||||
int status;
|
|
||||||
bool enabled;
|
|
||||||
uint32_t rawaddress;
|
|
||||||
uint32_t address;
|
|
||||||
uint32_t value;
|
|
||||||
uint32_t oldValue;
|
|
||||||
char codestring[20];
|
|
||||||
char desc[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
void cheatsAdd(const char* codeStr, const char* desc, uint32_t rawaddress, uint32_t address, uint32_t value,
|
void cheatsAdd(const char* codeStr, const char* desc, uint32_t rawaddress, uint32_t address, uint32_t value,
|
||||||
int code, int size);
|
int code, int size);
|
||||||
|
@ -47,6 +36,6 @@ void cheatsWriteByte(uint32_t address, uint8_t value);
|
||||||
int cheatsCheckKeys(uint32_t keys, uint32_t extended);
|
int cheatsCheckKeys(uint32_t keys, uint32_t extended);
|
||||||
|
|
||||||
extern int cheatsNumber;
|
extern int cheatsNumber;
|
||||||
extern CheatsData cheatsList[MAX_CHEATS];
|
extern core::CheatsData cheatsList[MAX_CHEATS];
|
||||||
|
|
||||||
#endif // VBAM_CORE_GBA_GBACHEATS_H_
|
#endif // VBAM_CORE_GBA_GBACHEATS_H_
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "vbam_rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "vbam_rust"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cbindgen = "0.26.0"
|
|
@ -0,0 +1,76 @@
|
||||||
|
#ifndef VBAM_CORE_RUST_H_
|
||||||
|
#define VBAM_CORE_RUST_H_
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace core {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
typedef enum CheatsDecodeError {
|
||||||
|
UnsupportedType,
|
||||||
|
InvalidLength,
|
||||||
|
InvalidCharacter,
|
||||||
|
AddressNotHex,
|
||||||
|
ValueNotHex,
|
||||||
|
} CheatsDecodeError;
|
||||||
|
|
||||||
|
typedef enum GbaCheatsType {
|
||||||
|
Generic,
|
||||||
|
GameSharkV2,
|
||||||
|
CodeBreaker,
|
||||||
|
ActionReplay,
|
||||||
|
} GbaCheatsType;
|
||||||
|
|
||||||
|
typedef struct CheatsData {
|
||||||
|
int code;
|
||||||
|
int size;
|
||||||
|
int status;
|
||||||
|
bool enabled;
|
||||||
|
uint32_t rawaddress;
|
||||||
|
uint32_t address;
|
||||||
|
uint32_t value;
|
||||||
|
uint32_t old_value;
|
||||||
|
char codestring[20];
|
||||||
|
char desc[32];
|
||||||
|
} CheatsData;
|
||||||
|
|
||||||
|
typedef enum Result_CheatsData__CheatsDecodeError_Tag {
|
||||||
|
Ok_CheatsData__CheatsDecodeError,
|
||||||
|
Err_CheatsData__CheatsDecodeError,
|
||||||
|
} Result_CheatsData__CheatsDecodeError_Tag;
|
||||||
|
|
||||||
|
typedef struct Result_CheatsData__CheatsDecodeError {
|
||||||
|
Result_CheatsData__CheatsDecodeError_Tag tag;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
struct CheatsData ok;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
enum CheatsDecodeError err;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} Result_CheatsData__CheatsDecodeError;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
enum GbaCheatsType some_type(void);
|
||||||
|
|
||||||
|
struct Result_CheatsData__CheatsDecodeError decode_code(enum GbaCheatsType cheat_type,
|
||||||
|
const char *code_string,
|
||||||
|
const char *description);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // namespace core
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif /* VBAM_CORE_RUST_H_ */
|
|
@ -0,0 +1,17 @@
|
||||||
|
extern crate cbindgen;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
|
||||||
|
cbindgen::Builder::new()
|
||||||
|
.with_crate(crate_dir)
|
||||||
|
.with_language(cbindgen::Language::C)
|
||||||
|
.with_cpp_compat(true)
|
||||||
|
.with_include_guard("VBAM_CORE_RUST_H_")
|
||||||
|
.with_namespace("core")
|
||||||
|
.generate()
|
||||||
|
.expect("Unable to generate bindings")
|
||||||
|
.write_to_file("bindings.hpp");
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
mod panic;
|
||||||
|
|
||||||
|
mod result;
|
||||||
|
pub use crate::base::result::Result;
|
||||||
|
|
||||||
|
mod string;
|
||||||
|
pub(crate) use crate::base::string::StrLike;
|
|
@ -0,0 +1,6 @@
|
||||||
|
#[panic_handler]
|
||||||
|
#[cfg(not(test))]
|
||||||
|
/// Panic handler, called on panic. Does nothing.
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum Result<T, E> {
|
||||||
|
Ok(T),
|
||||||
|
Err(E),
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
use core::ffi::c_char;
|
||||||
|
use core::ffi::CStr;
|
||||||
|
|
||||||
|
pub(crate) trait CharLike {
|
||||||
|
fn to_hex(&self) -> Option<u8>;
|
||||||
|
fn is_hex(&self) -> bool {
|
||||||
|
self.to_hex().is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharLike for u8 {
|
||||||
|
fn to_hex(&self) -> Option<u8> {
|
||||||
|
if *self >= b'0' && *self <= b'9' {
|
||||||
|
Some(*self - b'0')
|
||||||
|
} else if *self >= b'A' && *self <= b'F' {
|
||||||
|
Some(*self - b'A' + 10)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait StrLike {
|
||||||
|
fn to_hex(&self) -> Option<u32>;
|
||||||
|
fn clone_buffer<const LEN: usize>(&self) -> [c_char; LEN];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrLike for [u8] {
|
||||||
|
fn to_hex(&self) -> Option<u32> {
|
||||||
|
let mut result: u32 = 0;
|
||||||
|
for byte in self.iter() {
|
||||||
|
if let Some(value) = byte.to_hex() {
|
||||||
|
result = result.wrapping_mul(16).wrapping_add(value as u32);
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_buffer<const LEN: usize>(&self) -> [c_char; LEN] {
|
||||||
|
let mut buffer = [0; LEN];
|
||||||
|
let mut i: usize = 0;
|
||||||
|
for byte in self.iter() {
|
||||||
|
if i == LEN {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer[i] = *byte as c_char;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if i == LEN {
|
||||||
|
buffer[LEN - 1] = 0;
|
||||||
|
} else {
|
||||||
|
buffer[i] = 0;
|
||||||
|
}
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrLike for CStr {
|
||||||
|
fn to_hex(&self) -> Option<u32> {
|
||||||
|
self.to_bytes().to_hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_buffer<const LEN: usize>(&self) -> [c_char; LEN] {
|
||||||
|
self.to_bytes().clone_buffer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_char_to_hex() {
|
||||||
|
assert_eq!(b'0'.to_hex(), Some(0));
|
||||||
|
assert_eq!(b'9'.to_hex(), Some(9));
|
||||||
|
assert_eq!(b'A'.to_hex(), Some(10));
|
||||||
|
assert_eq!(b'F'.to_hex(), Some(15));
|
||||||
|
assert_eq!(b'G'.to_hex(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_str_to_hex() {
|
||||||
|
assert_eq!([].to_hex(), Some(0));
|
||||||
|
assert_eq!([b'0'].to_hex(), Some(0));
|
||||||
|
assert_eq!([b'1', b'0'].to_hex(), Some(16));
|
||||||
|
assert_eq!([b'F', b'F'].to_hex(), Some(255));
|
||||||
|
assert_eq!([b'G'].to_hex(), None);
|
||||||
|
assert_eq!(b"ABCDEF".to_hex(), Some(11259375));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_str_clone_buffer() {
|
||||||
|
assert_eq!(b"test".clone_buffer(), [116, 101, 115, 116, 0]);
|
||||||
|
assert_eq!(b"test".clone_buffer(), [116, 101, 0]);
|
||||||
|
assert_eq!(b"test".clone_buffer(), [0]);
|
||||||
|
assert_eq!(b"".clone_buffer(), [0]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
mod cheats;
|
||||||
|
pub use crate::gba::cheats::GbaCheatsType;
|
|
@ -0,0 +1,108 @@
|
||||||
|
use core::ffi::c_char;
|
||||||
|
use core::ffi::c_int;
|
||||||
|
use core::ffi::CStr;
|
||||||
|
|
||||||
|
use crate::base::StrLike;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum GbaCheatsType {
|
||||||
|
Generic,
|
||||||
|
GameSharkV2,
|
||||||
|
CodeBreaker,
|
||||||
|
ActionReplay,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GbaCheatsType {
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn some_type() -> GbaCheatsType {
|
||||||
|
GbaCheatsType::Generic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CheatsData {
|
||||||
|
code: c_int,
|
||||||
|
size: c_int,
|
||||||
|
status: c_int,
|
||||||
|
enabled: bool,
|
||||||
|
rawaddress: u32,
|
||||||
|
address: u32,
|
||||||
|
value: u32,
|
||||||
|
old_value: u32,
|
||||||
|
codestring: [c_char; 20],
|
||||||
|
desc: [c_char; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum CheatsDecodeError {
|
||||||
|
UnsupportedType,
|
||||||
|
InvalidLength,
|
||||||
|
InvalidCharacter,
|
||||||
|
AddressNotHex,
|
||||||
|
ValueNotHex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheatsData {
|
||||||
|
fn decode_generic(code_string: &CStr, description: &CStr) -> Result<CheatsData, CheatsDecodeError> {
|
||||||
|
let code_length = code_string.to_bytes().len();
|
||||||
|
if code_length != 11 && code_length != 13 && code_length != 17 {
|
||||||
|
return Err(CheatsDecodeError::InvalidLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
if code_string.to_bytes()[8] != b':' {
|
||||||
|
return Err(CheatsDecodeError::InvalidCharacter);
|
||||||
|
}
|
||||||
|
|
||||||
|
let address =
|
||||||
|
match code_string.to_bytes()[..8].to_hex() {
|
||||||
|
Some(address) => address,
|
||||||
|
None => {
|
||||||
|
return Err(CheatsDecodeError::AddressNotHex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let value =
|
||||||
|
match code_string.to_bytes()[9..].to_hex() {
|
||||||
|
Some(value) => value,
|
||||||
|
None => {
|
||||||
|
return Err(CheatsDecodeError::ValueNotHex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let code = if code_length == 1 {
|
||||||
|
0
|
||||||
|
} else if code_length == 13 {
|
||||||
|
114
|
||||||
|
} else {
|
||||||
|
115
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(CheatsData {
|
||||||
|
code,
|
||||||
|
size: code,
|
||||||
|
status: 0,
|
||||||
|
enabled: true,
|
||||||
|
rawaddress: address,
|
||||||
|
address,
|
||||||
|
value,
|
||||||
|
old_value: 0,
|
||||||
|
codestring: code_string.clone_buffer(),
|
||||||
|
desc: description.clone_buffer(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn decode_code(
|
||||||
|
cheat_type: GbaCheatsType,
|
||||||
|
code_string: *const c_char,
|
||||||
|
description: *const c_char,
|
||||||
|
) -> Result<CheatsData, CheatsDecodeError> {
|
||||||
|
let code = unsafe { CStr::from_ptr(code_string) };
|
||||||
|
let description = unsafe { CStr::from_ptr(description) };
|
||||||
|
match cheat_type {
|
||||||
|
GbaCheatsType::Generic => CheatsData::decode_generic(code, description),
|
||||||
|
_ => Err(CheatsDecodeError::UnsupportedType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
//! A crate implementing part of the VBA-M core in Rust. This is meant to be
|
||||||
|
//! used as a library in the VBA-M core.
|
||||||
|
//!
|
||||||
|
//! Guidelines:
|
||||||
|
//! * `no_std`. In particular, this means no I/O and no file I/O. It's fine to
|
||||||
|
//! pass buffers of memory to and from the Rust code, but the Rust code itself
|
||||||
|
//! should not perform any I/O.
|
||||||
|
//! * Core code only. We may want to use Rust in other parts of the codebase but
|
||||||
|
//! let's leave it at the core for now.
|
||||||
|
//! * Exported types must be `#[repr(C)]`. Exported functions must be `extern
|
||||||
|
//! "C"` with `[no_mangle]`.
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
pub mod base;
|
||||||
|
pub mod gba;
|
||||||
|
|
||||||
|
mod prelude {
|
||||||
|
pub use crate::base::Result;
|
||||||
|
pub use crate::base::Result::Err;
|
||||||
|
pub use crate::base::Result::Ok;
|
||||||
|
}
|
|
@ -34,10 +34,6 @@ if(MSVC)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_LIRC)
|
|
||||||
set(LIRC_CLIENT_LIBRARY lirc_client)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(vbam
|
target_link_libraries(vbam
|
||||||
vbam-core
|
vbam-core
|
||||||
vbam-components-audio-sdl
|
vbam-components-audio-sdl
|
||||||
|
|
|
@ -427,7 +427,7 @@ host_compile(${CMAKE_CURRENT_SOURCE_DIR}/bin2c.c ${BIN2C})
|
||||||
|
|
||||||
# Override wxrc when cross-compiling.
|
# Override wxrc when cross-compiling.
|
||||||
if(CMAKE_HOST_WIN32 AND CMAKE_CROSSCOMPILING)
|
if(CMAKE_HOST_WIN32 AND CMAKE_CROSSCOMPILING)
|
||||||
set(WXRC ${CMAKE_SOURCE_DIR}/dependencies/wxrc/wxrc.exe)
|
find_program(WXRC NAMES wxrc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Configure wxrc.
|
# Configure wxrc.
|
||||||
|
|
|
@ -8,6 +8,6 @@
|
||||||
#define DOCTEST_THREAD_LOCAL // Avoid MinGW thread_local bug.
|
#define DOCTEST_THREAD_LOCAL // Avoid MinGW thread_local bug.
|
||||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||||
|
|
||||||
#include "doctest.h"
|
#include <doctest.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -524,7 +524,6 @@ setup() {
|
||||||
# binary smaller.
|
# binary smaller.
|
||||||
if [ "$target_os" = windows ] && [ "$target_bits" -eq 32 ]; then
|
if [ "$target_os" = windows ] && [ "$target_bits" -eq 32 ]; then
|
||||||
BUILD_FFMPEG=
|
BUILD_FFMPEG=
|
||||||
PROJECT_ARGS="$PROJECT_ARGS -DENABLE_OPENAL=NO"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$BUILD_FFMPEG" ]; then
|
if [ -z "$BUILD_FFMPEG" ]; then
|
||||||
|
|
Loading…
Reference in New Issue