mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2024-11-07 15:15:05 +01:00
Build system & dependency refactoring
Switched to a makefile + clang build system Now builds as a library by default Removed SDL2 dependency Changed RT64 integration to use zilmar spec in order to pass a window handle Proper unaligned loads and stores implementation
This commit is contained in:
parent
73308e3500
commit
0fdfc5f7fe
10
MMRecomp.sln
10
MMRecomp.sln
@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.33027.164
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMRecomp", "MMRecomp.vcxproj", "{14B47028-6A86-4660-A86D-2E69F229E110}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMRecomp", "MMRecomp.vcxproj", "{14B47028-6A86-4660-A86D-2E69F229E110}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RecompiledFuncs", "RecompiledFuncs.vcxproj", "{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
@ -23,14 +21,6 @@ Global
|
|||||||
{14B47028-6A86-4660-A86D-2E69F229E110}.Release|x64.Build.0 = Release|x64
|
{14B47028-6A86-4660-A86D-2E69F229E110}.Release|x64.Build.0 = Release|x64
|
||||||
{14B47028-6A86-4660-A86D-2E69F229E110}.Release|x86.ActiveCfg = Release|Win32
|
{14B47028-6A86-4660-A86D-2E69F229E110}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{14B47028-6A86-4660-A86D-2E69F229E110}.Release|x86.Build.0 = Release|Win32
|
{14B47028-6A86-4660-A86D-2E69F229E110}.Release|x86.Build.0 = Release|Win32
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Release|x64.Build.0 = Release|x64
|
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{7BF5E3F9-C49F-4C84-AB64-7681F028CAC2}.Release|x86.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -40,13 +40,13 @@
|
|||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Makefile</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Makefile</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
@ -78,9 +78,15 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<LinkIncremental>true</LinkIncremental>
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<NMakeBuildCommandLine>make TARGET=$(Configuration) LIB_DIR="$(VC_LibraryPath_VC_x64_Desktop)" UCRT_DIR="$(UniversalCRT_LibraryPath_x64)" SDK_DIR="$(WindowsSDK_LibraryPath)\x64" -j$(NUMBER_OF_PROCESSORS)</NMakeBuildCommandLine>
|
||||||
|
<NMakeCleanCommandLine>make TARGET=$(Configuration) clean</NMakeCleanCommandLine>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<LinkIncremental>false</LinkIncremental>
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<NMakeBuildCommandLine>make TARGET=$(Configuration) LIB_DIR="$(VC_LibraryPath_VC_x64_Desktop)" UCRT_DIR="$(UniversalCRT_LibraryPath_x64)" SDK_DIR="$(WindowsSDK_LibraryPath)\x64" -j$(NUMBER_OF_PROCESSORS)</NMakeBuildCommandLine>
|
||||||
|
<NMakeCleanCommandLine>make TARGET=$(Configuration) clean</NMakeCleanCommandLine>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
@ -225,11 +231,6 @@ XCOPY "$(ProjectDir)lib\SDL2-2.24.0\lib\$(Platform)\SDL2.dll" "$(TargetDir)" /S
|
|||||||
<ClInclude Include="portultra\ultra64.h" />
|
<ClInclude Include="portultra\ultra64.h" />
|
||||||
<ClInclude Include="src\euc-jp.h" />
|
<ClInclude Include="src\euc-jp.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="RecompiledFuncs.vcxproj">
|
|
||||||
<Project>{7bf5e3f9-c49f-4c84-ab64-7681f028cac2}</Project>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
108
Makefile
Normal file
108
Makefile
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
CONFIG ?= Debug
|
||||||
|
LIB ?= 0
|
||||||
|
|
||||||
|
ifeq ($(CONFIG),Debug)
|
||||||
|
BUILD_DIR := build/debug
|
||||||
|
FUNC_OPTFLAGS := -Og -g -fno-strict-aliasing
|
||||||
|
OPTFLAGS := -Og -g -fno-strict-aliasing
|
||||||
|
# Static C runtime linking
|
||||||
|
LIBS := -Wl,/nodefaultlib:libcmt -Wl,/nodefaultlib:ucrt -Wl,/nodefaultlib:libucrt -llibcmtd -llibvcruntimed -llibucrtd
|
||||||
|
# Dynamic
|
||||||
|
# LIBS := -Wl,/nodefaultlib:libcmt -Wl,/nodefaultlib:ucrt -Wl,/nodefaultlib:libucrt -lmsvcrtd -lvcruntimed -lucrtd
|
||||||
|
else ifeq ($(CONFIG),Release)
|
||||||
|
BUILD_DIR := build/release
|
||||||
|
FUNC_OPTFLAGS := -O2 -g -fno-strict-aliasing
|
||||||
|
OPTFLAGS := -O2 -g -fno-strict-aliasing
|
||||||
|
# Static C runtime linking
|
||||||
|
LIBS := -Wl,/nodefaultlib:libcmt -Wl,/nodefaultlib:ucrt -Wl,/nodefaultlib:libucrt -llibcmt -llibvcruntime -llibucrt
|
||||||
|
# Dynamic
|
||||||
|
# LIBS := -Wl,/nodefaultlib:libcmt -Wl,/nodefaultlib:ucrt -Wl,/nodefaultlib:libucrt -lmsvcrt -lvcruntime -lucrt
|
||||||
|
else
|
||||||
|
$(error "Invalid build configuration: $(CONFIG)")
|
||||||
|
endif
|
||||||
|
|
||||||
|
SRC_DIRS := portultra src rsp
|
||||||
|
|
||||||
|
FUNCS_DIR := RecompiledFuncs
|
||||||
|
FUNCS_LIB := $(BUILD_DIR)/RecompiledFuncs.lib
|
||||||
|
FUNCS_C_SRCS := $(wildcard $(FUNCS_DIR)/*.c)
|
||||||
|
FUNCS_CXX_SRCS := $(wildcard $(FUNCS_DIR)/*.cpp)
|
||||||
|
|
||||||
|
FUNC_BUILD_DIR := $(BUILD_DIR)/RecompiledFuncs
|
||||||
|
FUNCS_C_OBJS := $(addprefix $(BUILD_DIR)/,$(FUNCS_C_SRCS:.c=.o))
|
||||||
|
FUNCS_CXX_OBJS := $(addprefix $(BUILD_DIR)/,$(FUNCS_CXX_SRCS:.cpp=.o))
|
||||||
|
ALL_FUNC_OBJS := $(FUNCS_C_OBJS) $(FUNCS_CXX_OBJS)
|
||||||
|
|
||||||
|
BUILD_SRC_DIRS := $(addprefix $(BUILD_DIR)/,$(SRC_DIRS))
|
||||||
|
C_SRCS := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
|
||||||
|
CXX_SRCS := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
|
||||||
|
|
||||||
|
C_OBJS := $(addprefix $(BUILD_DIR)/,$(C_SRCS:.c=.o))
|
||||||
|
CXX_OBJS := $(addprefix $(BUILD_DIR)/,$(CXX_SRCS:.cpp=.o))
|
||||||
|
ALL_OBJS := $(C_OBJS) $(CXX_OBJS)
|
||||||
|
|
||||||
|
|
||||||
|
CC := clang
|
||||||
|
CXX := clang++
|
||||||
|
LIB := clang++
|
||||||
|
LD := clang++
|
||||||
|
|
||||||
|
FUNC_CFLAGS := $(FUNC_OPTFLAGS) -c -Wno-unused-but-set-variable
|
||||||
|
FUNC_CXXFLAGS := $(FUNC_OPTFLAGS) -std=c++20 -c
|
||||||
|
FUNC_CPPFLAGS := -Iinclude
|
||||||
|
LIBFLAGS := $(OPTFLAGS) -fuse-ld=llvm-lib
|
||||||
|
LIB_DIR ?= C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\lib\x64
|
||||||
|
UCRT_DIR ?= C:\Program Files (x86)\Windows Kits\10\lib\10.0.22000.0\ucrt\x64;
|
||||||
|
SDK_DIR ?= C:\Program Files (x86)\Windows Kits\10\lib\10.0.22000.0\um\x64
|
||||||
|
|
||||||
|
WARNFLAGS := -Wall -Wextra -Wpedantic -Wno-gnu-anonymous-struct
|
||||||
|
CFLAGS := -ffunction-sections -fdata-sections $(OPTFLAGS) $(WARNFLAGS) -c
|
||||||
|
CXXFLAGS := -ffunction-sections -fdata-sections $(OPTFLAGS) $(WARNFLAGS) -std=c++20 -c
|
||||||
|
CPPFLAGS := -Iinclude -Ithirdparty
|
||||||
|
LDFLAGS := -v -Wl,/OPT:REF $(OPTFLAGS) $(LIBS) -L"$(LIB_DIR:;=)" -L"$(UCRT_DIR:;=)" -L"$(SDK_DIR:;=)" lib/RT64/$(CONFIG)/RT64.lib
|
||||||
|
|
||||||
|
ifeq ($(LIB),1)
|
||||||
|
TARGET := $(BUILD_DIR)/MMRecomp.dll
|
||||||
|
LDFLAGS += -shared
|
||||||
|
else
|
||||||
|
TARGET := $(BUILD_DIR)/MMRecomp.exe
|
||||||
|
endif
|
||||||
|
|
||||||
|
default: $(TARGET)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rmdir /S /Q $(subst /,\\,$(BUILD_DIR))
|
||||||
|
|
||||||
|
cleanfuncs:
|
||||||
|
|
||||||
|
|
||||||
|
$(FUNCS_CXX_OBJS) : $(BUILD_DIR)/%.o : %.cpp | $(FUNC_BUILD_DIR)
|
||||||
|
@$(CXX) $(FUNC_CXXFLAGS) $(FUNC_CPPFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
$(FUNCS_C_OBJS) : $(BUILD_DIR)/%.o : %.c | $(FUNC_BUILD_DIR)
|
||||||
|
@$(CC) $(FUNC_CFLAGS) $(FUNC_CPPFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
$(FUNCS_LIB): $(ALL_FUNC_OBJS) | $(BUILD_DIR)
|
||||||
|
$(LIB) $(LIBFLAGS) $(FUNC_BUILD_DIR)/*.o -o $@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$(CXX_OBJS) : $(BUILD_DIR)/%.o : %.cpp | $(BUILD_SRC_DIRS)
|
||||||
|
$(CXX) -MMD -MF $(@:.o=.d) $(CXXFLAGS) $(CPPFLAGS) $< -o $@
|
||||||
|
|
||||||
|
$(C_OBJS) : $(BUILD_DIR)/%.o : %.c | $(BUILD_SRC_DIRS)
|
||||||
|
$(CC) -MMD -MF $(@:.o=.d) $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||||
|
|
||||||
|
$(TARGET): $(FUNCS_LIB) $(ALL_OBJS) | $(BUILD_SRC_DIRS)
|
||||||
|
$(LD) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
$(BUILD_SRC_DIRS) $(FUNC_BUILD_DIR) $(BUILD_DIR):
|
||||||
|
mkdir $(subst /,\\,$@)
|
||||||
|
|
||||||
|
-include $(ALL_OBJS:.o=.d)
|
||||||
|
|
||||||
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
.SUFFIXES:
|
||||||
|
.PHONY: default clean cleanfuncs
|
||||||
|
|
||||||
|
print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
|
@ -66,27 +66,68 @@ static inline uint64_t load_doubleword(uint8_t* rdram, gpr reg, gpr offset) {
|
|||||||
#define LD(offset, reg) \
|
#define LD(offset, reg) \
|
||||||
load_doubleword(rdram, offset, reg)
|
load_doubleword(rdram, offset, reg)
|
||||||
|
|
||||||
// TODO proper lwl/lwr/swl/swr
|
static inline gpr do_lwl(uint8_t* rdram, gpr initial_value, gpr offset, gpr reg) {
|
||||||
static inline void do_swl(uint8_t* rdram, gpr offset, gpr reg, gpr val) {
|
// Calculate the overall address
|
||||||
uint8_t byte0 = (uint8_t)(val >> 24);
|
gpr address = (offset + reg);
|
||||||
uint8_t byte1 = (uint8_t)(val >> 16);
|
|
||||||
uint8_t byte2 = (uint8_t)(val >> 8);
|
|
||||||
uint8_t byte3 = (uint8_t)(val >> 0);
|
|
||||||
|
|
||||||
MEM_B(offset + 0, reg) = byte0;
|
// Load the aligned word
|
||||||
MEM_B(offset + 1, reg) = byte1;
|
gpr word_address = address & ~0x3;
|
||||||
MEM_B(offset + 2, reg) = byte2;
|
uint32_t loaded_value = MEM_W(0, word_address);
|
||||||
MEM_B(offset + 3, reg) = byte3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline gpr do_lwl(uint8_t* rdram, gpr offset, gpr reg) {
|
// Mask the existing value and shift the loaded value appropriately
|
||||||
uint8_t byte0 = MEM_B(offset + 0, reg);
|
gpr misalignment = address & 0x3;
|
||||||
uint8_t byte1 = MEM_B(offset + 1, reg);
|
gpr masked_value = initial_value & ~(0xFFFFFFFFu << (misalignment * 8));
|
||||||
uint8_t byte2 = MEM_B(offset + 2, reg);
|
loaded_value <<= (misalignment * 8);
|
||||||
uint8_t byte3 = MEM_B(offset + 3, reg);
|
|
||||||
|
|
||||||
// Cast to int32_t to sign extend first
|
// Cast to int32_t to sign extend first
|
||||||
return (gpr)(int32_t)((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0));
|
return (gpr)(int32_t)(masked_value | loaded_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gpr do_lwr(uint8_t* rdram, gpr initial_value, gpr offset, gpr reg) {
|
||||||
|
// Calculate the overall address
|
||||||
|
gpr address = (offset + reg);
|
||||||
|
|
||||||
|
// Load the aligned word
|
||||||
|
gpr word_address = address & ~0x3;
|
||||||
|
uint32_t loaded_value = MEM_W(0, word_address);
|
||||||
|
|
||||||
|
// Mask the existing value and shift the loaded value appropriately
|
||||||
|
gpr misalignment = address & 0x3;
|
||||||
|
gpr masked_value = initial_value & ~(0xFFFFFFFFu >> (24 - misalignment * 8));
|
||||||
|
loaded_value >>= (24 - misalignment * 8);
|
||||||
|
|
||||||
|
// Cast to int32_t to sign extend first
|
||||||
|
return (gpr)(int32_t)(masked_value | loaded_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void do_swl(uint8_t* rdram, gpr offset, gpr reg, gpr val) {
|
||||||
|
// Calculate the overall address
|
||||||
|
gpr address = (offset + reg);
|
||||||
|
|
||||||
|
// Get the initial value of the aligned word
|
||||||
|
gpr word_address = address & ~0x3;
|
||||||
|
uint32_t initial_value = MEM_W(0, word_address);
|
||||||
|
|
||||||
|
// Mask the initial value and shift the input value appropriately
|
||||||
|
gpr misalignment = address & 0x3;
|
||||||
|
uint32_t masked_initial_value = initial_value & ~(0xFFFFFFFFu >> (misalignment * 8));
|
||||||
|
uint32_t shifted_input_value = ((uint32_t)val) >> (misalignment * 8);
|
||||||
|
MEM_W(0, word_address) = masked_initial_value | shifted_input_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void do_swr(uint8_t* rdram, gpr offset, gpr reg, gpr val) {
|
||||||
|
// Calculate the overall address
|
||||||
|
gpr address = (offset + reg);
|
||||||
|
|
||||||
|
// Get the initial value of the aligned word
|
||||||
|
gpr word_address = address & ~0x3;
|
||||||
|
uint32_t initial_value = MEM_W(0, word_address);
|
||||||
|
|
||||||
|
// Mask the initial value and shift the input value appropriately
|
||||||
|
gpr misalignment = address & 0x3;
|
||||||
|
uint32_t masked_initial_value = initial_value & ~(0xFFFFFFFFu << (24 - misalignment * 8));
|
||||||
|
uint32_t shifted_input_value = ((uint32_t)val) << (24 - misalignment * 8);
|
||||||
|
MEM_W(0, word_address) = masked_initial_value | shifted_input_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define S32(val) \
|
#define S32(val) \
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
#define __RT64_LAYER_H__
|
#define __RT64_LAYER_H__
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
void* hWnd;
|
||||||
|
void* hStatusBar;
|
||||||
|
|
||||||
|
int Reserved;
|
||||||
|
|
||||||
unsigned char* HEADER; /* This is the rom header (first 40h bytes of the rom) */
|
unsigned char* HEADER; /* This is the rom header (first 40h bytes of the rom) */
|
||||||
unsigned char* RDRAM;
|
unsigned char* RDRAM;
|
||||||
unsigned char* DMEM;
|
unsigned char* DMEM;
|
||||||
@ -35,9 +40,9 @@ typedef struct {
|
|||||||
|
|
||||||
void (*CheckInterrupts)(void);
|
void (*CheckInterrupts)(void);
|
||||||
|
|
||||||
unsigned int version;
|
// unsigned int version;
|
||||||
unsigned int* SP_STATUS_REG;
|
// unsigned int* SP_STATUS_REG;
|
||||||
const unsigned int* RDRAM_SIZE;
|
// const unsigned int* RDRAM_SIZE;
|
||||||
} GFX_INFO;
|
} GFX_INFO;
|
||||||
|
|
||||||
#define DLLEXPORT extern "C" __declspec(dllexport)
|
#define DLLEXPORT extern "C" __declspec(dllexport)
|
||||||
@ -56,6 +61,7 @@ DLLIMPORT void ProcessRDPList(void);
|
|||||||
DLLIMPORT void ProcessDList(void);
|
DLLIMPORT void ProcessDList(void);
|
||||||
DLLIMPORT void UpdateScreen(void);
|
DLLIMPORT void UpdateScreen(void);
|
||||||
DLLIMPORT void PumpEvents(void);
|
DLLIMPORT void PumpEvents(void);
|
||||||
|
DLLIMPORT void ChangeWindow(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,55 +1,39 @@
|
|||||||
#include "ultra64.h"
|
#include "ultra64.h"
|
||||||
#include "multilibultra.hpp"
|
#include "multilibultra.hpp"
|
||||||
#include "SDL.h"
|
|
||||||
#include "SDL_audio.h"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
static SDL_AudioDeviceID audio_device = 0;
|
|
||||||
static uint32_t sample_rate = 48000;
|
static uint32_t sample_rate = 48000;
|
||||||
|
|
||||||
|
static Multilibultra::audio_callbacks_t audio_callbacks;
|
||||||
|
|
||||||
|
void Multilibultra::set_audio_callbacks(const audio_callbacks_t* callbacks) {
|
||||||
|
if (callbacks != nullptr) {
|
||||||
|
audio_callbacks = *callbacks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Multilibultra::init_audio() {
|
void Multilibultra::init_audio() {
|
||||||
// Initialize SDL audio.
|
|
||||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
|
||||||
// Pick an initial dummy sample rate; this will be set by the game later to the true sample rate.
|
// Pick an initial dummy sample rate; this will be set by the game later to the true sample rate.
|
||||||
set_audio_frequency(48000);
|
set_audio_frequency(48000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Multilibultra::set_audio_frequency(uint32_t freq) {
|
void Multilibultra::set_audio_frequency(uint32_t freq) {
|
||||||
if (audio_device != 0) {
|
if (audio_callbacks.set_frequency) {
|
||||||
SDL_CloseAudioDevice(audio_device);
|
audio_callbacks.set_frequency(freq);
|
||||||
}
|
}
|
||||||
SDL_AudioSpec spec_desired{
|
|
||||||
.freq = (int)freq,
|
|
||||||
.format = AUDIO_S16,
|
|
||||||
.channels = 2,
|
|
||||||
.silence = 0, // calculated
|
|
||||||
.samples = 0x100, // Fairly small sample count to reduce the latency of internal buffering
|
|
||||||
.padding = 0, // unused
|
|
||||||
.size = 0, // calculated
|
|
||||||
.callback = nullptr,//feed_audio, // Use a callback as QueueAudio causes popping
|
|
||||||
.userdata = nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
audio_device = SDL_OpenAudioDevice(nullptr, false, &spec_desired, nullptr, 0);
|
|
||||||
if (audio_device == 0) {
|
|
||||||
printf("SDL Error: %s\n", SDL_GetError());
|
|
||||||
fflush(stdout);
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
SDL_PauseAudioDevice(audio_device, 0);
|
|
||||||
sample_rate = freq;
|
sample_rate = freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Multilibultra::queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data_, uint32_t byte_count) {
|
void Multilibultra::queue_audio_buffer(RDRAM_ARG PTR(int16_t) audio_data_, uint32_t byte_count) {
|
||||||
// Buffer for holding the output of swapping the audio channels. This is reused across
|
// Buffer for holding the output of swapping the audio channels. This is reused across
|
||||||
// calls to reduce runtime allocations.
|
// calls to reduce runtime allocations.
|
||||||
static std::vector<uint16_t> swap_buffer;
|
static std::vector<int16_t> swap_buffer;
|
||||||
|
|
||||||
// Ensure that the byte count is an integer multiple of samples.
|
// Ensure that the byte count is an integer multiple of samples.
|
||||||
assert((byte_count & 1) == 0);
|
assert((byte_count & 1) == 0);
|
||||||
|
|
||||||
// Calculate the number of samples from the number of bytes.
|
// Calculate the number of samples from the number of bytes.
|
||||||
uint32_t sample_count = byte_count / sizeof(s16);
|
uint32_t sample_count = byte_count / sizeof(int16_t);
|
||||||
|
|
||||||
// Make sure the swap buffer is large enough to hold all the incoming audio data.
|
// Make sure the swap buffer is large enough to hold all the incoming audio data.
|
||||||
if (sample_count > swap_buffer.size()) {
|
if (sample_count > swap_buffer.size()) {
|
||||||
@ -57,34 +41,45 @@ void Multilibultra::queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data_, uint32_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Swap the audio channels into the swap buffer to correct for the address xor caused by endianness handling.
|
// Swap the audio channels into the swap buffer to correct for the address xor caused by endianness handling.
|
||||||
s16* audio_data = TO_PTR(s16, audio_data_);
|
int16_t* audio_data = TO_PTR(int16_t, audio_data_);
|
||||||
for (size_t i = 0; i < sample_count; i += 2) {
|
for (size_t i = 0; i < sample_count; i += 2) {
|
||||||
swap_buffer[i + 0] = audio_data[i + 1];
|
swap_buffer[i + 0] = audio_data[i + 1];
|
||||||
swap_buffer[i + 1] = audio_data[i + 0];
|
swap_buffer[i + 1] = audio_data[i + 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue the swapped audio data.
|
// Queue the swapped audio data.
|
||||||
SDL_QueueAudio(audio_device, swap_buffer.data(), byte_count);
|
if (audio_callbacks.queue_samples) {
|
||||||
|
audio_callbacks.queue_samples(swap_buffer.data(), sample_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t buffer_offset_frames = 1;
|
// For SDL2
|
||||||
|
//uint32_t buffer_offset_frames = 1;
|
||||||
|
// For Godot
|
||||||
|
float buffer_offset_frames = 0.5f;
|
||||||
|
|
||||||
// If there's ever any audio popping, check here first. Some games are very sensitive to
|
// If there's ever any audio popping, check here first. Some games are very sensitive to
|
||||||
// the remaining sample count and reporting a number that's too high here can lead to issues.
|
// the remaining sample count and reporting a number that's too high here can lead to issues.
|
||||||
// Reporting a number that's too low can lead to audio lag in some games.
|
// Reporting a number that's too low can lead to audio lag in some games.
|
||||||
uint32_t Multilibultra::get_remaining_audio_bytes() {
|
uint32_t Multilibultra::get_remaining_audio_bytes() {
|
||||||
// Get the number of remaining buffered audio bytes.
|
// Get the number of remaining buffered audio bytes.
|
||||||
uint32_t buffered_byte_count = SDL_GetQueuedAudioSize(audio_device);
|
uint32_t buffered_byte_count;
|
||||||
|
if (audio_callbacks.get_samples_remaining()) {
|
||||||
// Adjust the reported count to be some number of refreshes in the future, which helps ensure that
|
buffered_byte_count = audio_callbacks.get_samples_remaining() * sizeof(int16_t);
|
||||||
// there are enough samples even if the audio thread experiences a small amount of lag. This prevents
|
|
||||||
// audio popping on games that use the buffered audio byte count to determine how many samples
|
|
||||||
// to generate.
|
|
||||||
uint32_t samples_per_vi = (sample_rate / 60);
|
|
||||||
if (buffered_byte_count > (buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) {
|
|
||||||
buffered_byte_count -= (buffer_offset_frames * sizeof(int16_t) * samples_per_vi);
|
|
||||||
} else {
|
|
||||||
buffered_byte_count = 0;
|
|
||||||
}
|
}
|
||||||
return buffered_byte_count;
|
else {
|
||||||
|
buffered_byte_count = 100;
|
||||||
|
}
|
||||||
|
// Adjust the reported count to be some number of refreshes in the future, which helps ensure that
|
||||||
|
// there are enough samples even if the audio thread experiences a small amount of lag. This prevents
|
||||||
|
// audio popping on games that use the buffered audio byte count to determine how many samples
|
||||||
|
// to generate.
|
||||||
|
uint32_t samples_per_vi = (sample_rate / 60);
|
||||||
|
if (buffered_byte_count > static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) {
|
||||||
|
buffered_byte_count -= static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buffered_byte_count = 0;
|
||||||
|
}
|
||||||
|
return buffered_byte_count;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include "SDL.h"
|
|
||||||
#include "blockingconcurrentqueue.h"
|
#include "blockingconcurrentqueue.h"
|
||||||
|
|
||||||
#include "ultra64.h"
|
#include "ultra64.h"
|
||||||
@ -154,57 +153,10 @@ void dp_complete() {
|
|||||||
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RT64Init(uint8_t* rom, uint8_t* rdram);
|
void RT64Init(uint8_t* rom, uint8_t* rdram, void* window_handle);
|
||||||
void RT64SendDL(uint8_t* rdram, const OSTask* task);
|
void RT64SendDL(uint8_t* rdram, const OSTask* task);
|
||||||
void RT64UpdateScreen(uint32_t vi_origin);
|
void RT64UpdateScreen(uint32_t vi_origin);
|
||||||
|
void RT64ChangeWindow();
|
||||||
std::unordered_map<SDL_Scancode, int> button_map{
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_LEFT, 0x0002 }, // c left
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_RIGHT, 0x0001 }, // c right
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_UP, 0x0008 }, // c up
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_DOWN, 0x0004 }, // c down
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_RETURN, 0x1000 }, // start
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_SPACE, 0x8000 }, // a
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_LSHIFT, 0x4000 }, // b
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_Q, 0x2000 }, // z
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_E, 0x0020 }, // l
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_R, 0x0010 }, // r
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_J, 0x0200 }, // dpad left
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_L, 0x0100 }, // dpad right
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_I, 0x0800 }, // dpad up
|
|
||||||
{ SDL_Scancode::SDL_SCANCODE_K, 0x0400 }, // dpad down
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int button;
|
|
||||||
extern int stick_x;
|
|
||||||
extern int stick_y;
|
|
||||||
|
|
||||||
int sdl_event_filter(void* userdata, SDL_Event* event) {
|
|
||||||
switch (event->type) {
|
|
||||||
case SDL_EventType::SDL_KEYUP:
|
|
||||||
case SDL_EventType::SDL_KEYDOWN:
|
|
||||||
{
|
|
||||||
const Uint8* key_states = SDL_GetKeyboardState(nullptr);
|
|
||||||
int new_button = 0;
|
|
||||||
|
|
||||||
for (const auto& mapping : button_map) {
|
|
||||||
if (key_states[mapping.first]) {
|
|
||||||
new_button |= mapping.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button = new_button;
|
|
||||||
|
|
||||||
stick_x = 85 * (key_states[SDL_Scancode::SDL_SCANCODE_D] - key_states[SDL_Scancode::SDL_SCANCODE_A]);
|
|
||||||
stick_y = 85 * (key_states[SDL_Scancode::SDL_SCANCODE_W] - key_states[SDL_Scancode::SDL_SCANCODE_S]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_EventType::SDL_QUIT:
|
|
||||||
std::quick_exit(ERROR_SUCCESS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t dmem[0x1000];
|
uint8_t dmem[0x1000];
|
||||||
uint16_t rspReciprocals[512];
|
uint16_t rspReciprocals[512];
|
||||||
@ -276,18 +228,9 @@ void task_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_rea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready) {
|
void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready, void* window_handle) {
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
|
RT64Init(rom, rdram, window_handle);
|
||||||
fprintf(stderr, "Failed to initialize SDL2: %s\n", SDL_GetError());
|
|
||||||
std::quick_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
RT64Init(rom, rdram);
|
|
||||||
SDL_Window* window = SDL_GetWindowFromID(1);
|
|
||||||
// TODO set this window title in RT64, create the window here and send it to RT64, or something else entirely
|
|
||||||
// as the current window name visibly changes as RT64 is initialized
|
|
||||||
SDL_SetWindowTitle(window, "Recomp");
|
|
||||||
//SDL_SetEventFilter(sdl_event_filter, nullptr);
|
|
||||||
|
|
||||||
rsp_constants_init();
|
rsp_constants_init();
|
||||||
|
|
||||||
@ -318,15 +261,6 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read
|
|||||||
RT64UpdateScreen(swap_action->origin);
|
RT64UpdateScreen(swap_action->origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle events
|
|
||||||
constexpr int max_events_per_frame = 16;
|
|
||||||
SDL_Event cur_event;
|
|
||||||
int i = 0;
|
|
||||||
while (i++ < max_events_per_frame && SDL_PollEvent(&cur_event)) {
|
|
||||||
sdl_event_filter(nullptr, &cur_event);
|
|
||||||
}
|
|
||||||
//SDL_PumpEvents();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,11 +417,11 @@ void Multilibultra::send_si_message() {
|
|||||||
osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK);
|
osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Multilibultra::init_events(uint8_t* rdram, uint8_t* rom) {
|
void Multilibultra::init_events(uint8_t* rdram, uint8_t* rom, void* window_handle) {
|
||||||
std::atomic_flag gfx_thread_ready;
|
std::atomic_flag gfx_thread_ready;
|
||||||
std::atomic_flag task_thread_ready;
|
std::atomic_flag task_thread_ready;
|
||||||
events_context.rdram = rdram;
|
events_context.rdram = rdram;
|
||||||
events_context.sp.gfx_thread = std::thread{ gfx_thread_func, rdram, rom, &gfx_thread_ready };
|
events_context.sp.gfx_thread = std::thread{ gfx_thread_func, rdram, rom, &gfx_thread_ready, window_handle };
|
||||||
events_context.sp.task_thread = std::thread{ task_thread_func, rdram, rom, &task_thread_ready };
|
events_context.sp.task_thread = std::thread{ task_thread_func, rdram, rom, &task_thread_ready };
|
||||||
|
|
||||||
// Wait for the two sp threads to be ready before continuing to prevent the game from
|
// Wait for the two sp threads to be ready before continuing to prevent the game from
|
||||||
|
@ -21,10 +21,10 @@ constexpr int32_t cart_handle = 0x80800000;
|
|||||||
constexpr int32_t flash_handle = (int32_t)(cart_handle + sizeof(OSPiHandle));
|
constexpr int32_t flash_handle = (int32_t)(cart_handle + sizeof(OSPiHandle));
|
||||||
constexpr uint32_t save_size = 1024 * 1024 / 8; // Maximum save size, 1Mbit for flash
|
constexpr uint32_t save_size = 1024 * 1024 / 8; // Maximum save size, 1Mbit for flash
|
||||||
|
|
||||||
void preinit(uint8_t* rdram, uint8_t* rom);
|
void preinit(uint8_t* rdram, uint8_t* rom, void* window_handle);
|
||||||
void save_init();
|
void save_init();
|
||||||
void init_scheduler();
|
void init_scheduler();
|
||||||
void init_events(uint8_t* rdram, uint8_t* rom);
|
void init_events(uint8_t* rdram, uint8_t* rom, void* window_handle);
|
||||||
void init_timers(RDRAM_ARG1);
|
void init_timers(RDRAM_ARG1);
|
||||||
void set_self_paused(RDRAM_ARG1);
|
void set_self_paused(RDRAM_ARG1);
|
||||||
void wait_for_resumed(RDRAM_ARG1);
|
void wait_for_resumed(RDRAM_ARG1);
|
||||||
@ -46,11 +46,30 @@ void send_si_message();
|
|||||||
uint32_t get_speed_multiplier();
|
uint32_t get_speed_multiplier();
|
||||||
std::chrono::system_clock::time_point get_start();
|
std::chrono::system_clock::time_point get_start();
|
||||||
std::chrono::system_clock::duration time_since_start();
|
std::chrono::system_clock::duration time_since_start();
|
||||||
|
|
||||||
|
// Audio
|
||||||
void init_audio();
|
void init_audio();
|
||||||
void set_audio_frequency(uint32_t freq);
|
void set_audio_frequency(uint32_t freq);
|
||||||
void queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data, uint32_t byte_count);
|
void queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data, uint32_t byte_count);
|
||||||
uint32_t get_remaining_audio_bytes();
|
uint32_t get_remaining_audio_bytes();
|
||||||
|
|
||||||
|
struct audio_callbacks_t {
|
||||||
|
using queue_samples_t = void(int16_t*, size_t);
|
||||||
|
using get_samples_remaining_t = size_t();
|
||||||
|
using set_frequency_t = void(uint32_t);
|
||||||
|
queue_samples_t* queue_samples;
|
||||||
|
get_samples_remaining_t* get_samples_remaining;
|
||||||
|
set_frequency_t* set_frequency;
|
||||||
|
};
|
||||||
|
void set_audio_callbacks(const audio_callbacks_t* callbacks);
|
||||||
|
|
||||||
|
// Input
|
||||||
|
struct input_callbacks_t {
|
||||||
|
using get_input_t = void(uint16_t*, float*, float*);
|
||||||
|
get_input_t* get_input;
|
||||||
|
};
|
||||||
|
void set_input_callbacks(const input_callbacks_t* callback);
|
||||||
|
|
||||||
class preemption_guard {
|
class preemption_guard {
|
||||||
public:
|
public:
|
||||||
preemption_guard();
|
preemption_guard();
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include "ultra64.h"
|
#include "ultra64.h"
|
||||||
#include "multilibultra.hpp"
|
#include "multilibultra.hpp"
|
||||||
|
|
||||||
void Multilibultra::preinit(uint8_t* rdram, uint8_t* rom) {
|
void Multilibultra::preinit(uint8_t* rdram, uint8_t* rom, void* window_handle) {
|
||||||
Multilibultra::set_main_thread();
|
Multilibultra::set_main_thread();
|
||||||
Multilibultra::init_events(rdram, rom);
|
Multilibultra::init_events(rdram, rom, window_handle);
|
||||||
Multilibultra::init_timers(rdram);
|
Multilibultra::init_timers(rdram);
|
||||||
Multilibultra::init_audio();
|
Multilibultra::init_audio();
|
||||||
Multilibultra::save_init();
|
Multilibultra::save_init();
|
||||||
@ -11,5 +11,4 @@ void Multilibultra::preinit(uint8_t* rdram, uint8_t* rom) {
|
|||||||
|
|
||||||
extern "C" void osInitialize() {
|
extern "C" void osInitialize() {
|
||||||
Multilibultra::init_scheduler();
|
Multilibultra::init_scheduler();
|
||||||
//Multilibultra::native_init();
|
|
||||||
}
|
}
|
||||||
|
34
src/cont.cpp
34
src/cont.cpp
@ -1,6 +1,14 @@
|
|||||||
#include "../portultra/multilibultra.hpp"
|
#include "../portultra/multilibultra.hpp"
|
||||||
#include "recomp.h"
|
#include "recomp.h"
|
||||||
|
|
||||||
|
static Multilibultra::input_callbacks_t input_callbacks;
|
||||||
|
|
||||||
|
void Multilibultra::set_input_callbacks(const input_callbacks_t* callbacks) {
|
||||||
|
if (callbacks != nullptr) {
|
||||||
|
input_callbacks = *callbacks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int max_controllers = 0;
|
static int max_controllers = 0;
|
||||||
|
|
||||||
extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) {
|
extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||||
@ -37,28 +45,24 @@ struct OSContPad {
|
|||||||
u8 errno_;
|
u8 errno_;
|
||||||
};
|
};
|
||||||
|
|
||||||
int button = 0;
|
|
||||||
int stick_x = 0;
|
|
||||||
int stick_y = 0;
|
|
||||||
|
|
||||||
void press_button(int button) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void release_button(int button) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
|
extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||||
int32_t pad = (int32_t)ctx->r4;
|
int32_t pad = (int32_t)ctx->r4;
|
||||||
|
|
||||||
|
uint16_t buttons = 0;
|
||||||
|
float x = 0.0f;
|
||||||
|
float y = 0.0f;
|
||||||
|
|
||||||
|
if (input_callbacks.get_input) {
|
||||||
|
input_callbacks.get_input(&buttons, &x, &y);
|
||||||
|
}
|
||||||
|
|
||||||
if (max_controllers > 0) {
|
if (max_controllers > 0) {
|
||||||
// button
|
// button
|
||||||
MEM_H(0, pad) = button;
|
MEM_H(0, pad) = buttons;
|
||||||
// stick_x
|
// stick_x
|
||||||
MEM_B(2, pad) = stick_x;
|
MEM_B(2, pad) = (int8_t)(127 * x);
|
||||||
// stick_y
|
// stick_y
|
||||||
MEM_B(3, pad) = stick_y;
|
MEM_B(3, pad) = (int8_t)(127 * y);
|
||||||
// errno
|
// errno
|
||||||
MEM_B(4, pad) = 0;
|
MEM_B(4, pad) = 0;
|
||||||
}
|
}
|
||||||
|
@ -69,30 +69,10 @@ extern "C" void unload_overlays(int32_t ram_addr, uint32_t size);
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
std::unique_ptr<uint8_t[]> rdram_buffer;
|
||||||
//if (argc != 2) {
|
recomp_context context{};
|
||||||
// printf("Usage: %s [baserom]\n", argv[0]);
|
|
||||||
// exit(EXIT_SUCCESS);
|
|
||||||
//}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Set up console output to accept UTF-8 on windows
|
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
|
||||||
|
|
||||||
// Change to a font that supports Japanese characters
|
|
||||||
CONSOLE_FONT_INFOEX cfi;
|
|
||||||
cfi.cbSize = sizeof cfi;
|
|
||||||
cfi.nFont = 0;
|
|
||||||
cfi.dwFontSize.X = 0;
|
|
||||||
cfi.dwFontSize.Y = 16;
|
|
||||||
cfi.FontFamily = FF_DONTCARE;
|
|
||||||
cfi.FontWeight = FW_NORMAL;
|
|
||||||
wcscpy_s(cfi.FaceName, L"NSimSun");
|
|
||||||
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
|
|
||||||
#else
|
|
||||||
std::setlocale(LC_ALL, "en_US.UTF-8");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
__declspec(dllexport) extern "C" void init() {
|
||||||
{
|
{
|
||||||
std::basic_ifstream<uint8_t> rom_file{ get_rom_name(), std::ios::binary };
|
std::basic_ifstream<uint8_t> rom_file{ get_rom_name(), std::ios::binary };
|
||||||
|
|
||||||
@ -128,9 +108,8 @@ int main(int argc, char **argv) {
|
|||||||
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
|
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
|
||||||
|
|
||||||
// Allocate rdram_buffer (16MB to give room for any extra addressable data used by recomp)
|
// Allocate rdram_buffer (16MB to give room for any extra addressable data used by recomp)
|
||||||
std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(16 * 1024 * 1024);
|
rdram_buffer = std::make_unique<uint8_t[]>(16 * 1024 * 1024);
|
||||||
std::memset(rdram_buffer.get(), 0, 8 * 1024 * 1024);
|
std::memset(rdram_buffer.get(), 0, 8 * 1024 * 1024);
|
||||||
recomp_context context{};
|
|
||||||
|
|
||||||
// Initial 1MB DMA (rom address 0x1000 = physical address 0x10001000)
|
// Initial 1MB DMA (rom address 0x1000 = physical address 0x10001000)
|
||||||
do_rom_read(rdram_buffer.get(), entrypoint, 0x10001000, 0x100000);
|
do_rom_read(rdram_buffer.get(), entrypoint, 0x10001000, 0x100000);
|
||||||
@ -152,14 +131,46 @@ int main(int argc, char **argv) {
|
|||||||
MEM_W(osRomBase, 0) = 0xB0000000u; // standard rom base
|
MEM_W(osRomBase, 0) = 0xB0000000u; // standard rom base
|
||||||
MEM_W(osResetType, 0) = 0; // cold reset
|
MEM_W(osResetType, 0) = 0; // cold reset
|
||||||
MEM_W(osMemSize, 0) = 8 * 1024 * 1024; // 8MB
|
MEM_W(osMemSize, 0) = 8 * 1024 * 1024; // 8MB
|
||||||
|
}
|
||||||
|
|
||||||
debug_printf("[Recomp] Starting\n");
|
__declspec(dllexport) extern "C" void start(void* window_handle, const Multilibultra::audio_callbacks_t* audio_callbacks, const Multilibultra::input_callbacks_t* input_callbacks) {
|
||||||
|
Multilibultra::set_audio_callbacks(audio_callbacks);
|
||||||
|
Multilibultra::set_input_callbacks(input_callbacks);
|
||||||
|
std::thread game_thread{[](void* window_handle) {
|
||||||
|
debug_printf("[Recomp] Starting\n");
|
||||||
|
|
||||||
Multilibultra::preinit(rdram_buffer.get(), rom.get());
|
Multilibultra::preinit(rdram_buffer.get(), rom.get(), window_handle);
|
||||||
|
|
||||||
recomp_entrypoint(rdram_buffer.get(), &context);
|
recomp_entrypoint(rdram_buffer.get(), &context);
|
||||||
|
|
||||||
debug_printf("[Recomp] Quitting\n");
|
debug_printf("[Recomp] Quitting\n");
|
||||||
|
}, window_handle};
|
||||||
|
|
||||||
|
game_thread.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Set up console output to accept UTF-8 on windows
|
||||||
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
|
||||||
|
// Change to a font that supports Japanese characters
|
||||||
|
CONSOLE_FONT_INFOEX cfi;
|
||||||
|
cfi.cbSize = sizeof cfi;
|
||||||
|
cfi.nFont = 0;
|
||||||
|
cfi.dwFontSize.X = 0;
|
||||||
|
cfi.dwFontSize.Y = 16;
|
||||||
|
cfi.FontFamily = FF_DONTCARE;
|
||||||
|
cfi.FontWeight = FW_NORMAL;
|
||||||
|
wcscpy_s(cfi.FaceName, L"NSimSun");
|
||||||
|
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
|
||||||
|
#else
|
||||||
|
std::setlocale(LC_ALL, "en_US.UTF-8");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
init();
|
||||||
|
start(nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "../portultra/multilibultra.hpp"
|
#include "../portultra/multilibultra.hpp"
|
||||||
#include "rt64_layer.h"
|
#include "rt64_layer.h"
|
||||||
#include "SDL.h"
|
|
||||||
|
|
||||||
static uint8_t DMEM[0x1000];
|
static uint8_t DMEM[0x1000];
|
||||||
static uint8_t IMEM[0x1000];
|
static uint8_t IMEM[0x1000];
|
||||||
@ -44,7 +43,7 @@ void dummy_check_interrupts() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RT64Init(uint8_t* rom, uint8_t* rdram) {
|
void RT64Init(uint8_t* rom, uint8_t* rdram, void* window_handle) {
|
||||||
// Dynamic loading
|
// Dynamic loading
|
||||||
//auto RT64 = LoadLibrary("RT64.dll");
|
//auto RT64 = LoadLibrary("RT64.dll");
|
||||||
//if (RT64 == 0) {
|
//if (RT64 == 0) {
|
||||||
@ -57,6 +56,9 @@ void RT64Init(uint8_t* rom, uint8_t* rdram) {
|
|||||||
//GET_FUNC(RT64, UpdateScreen);
|
//GET_FUNC(RT64, UpdateScreen);
|
||||||
|
|
||||||
GFX_INFO gfx_info{};
|
GFX_INFO gfx_info{};
|
||||||
|
gfx_info.hWnd = window_handle;
|
||||||
|
gfx_info.hStatusBar = nullptr;
|
||||||
|
|
||||||
gfx_info.HEADER = rom;
|
gfx_info.HEADER = rom;
|
||||||
gfx_info.RDRAM = rdram;
|
gfx_info.RDRAM = rdram;
|
||||||
gfx_info.DMEM = DMEM;
|
gfx_info.DMEM = DMEM;
|
||||||
@ -89,9 +91,6 @@ void RT64Init(uint8_t* rom, uint8_t* rdram) {
|
|||||||
gfx_info.VI_Y_SCALE_REG = &VI_Y_SCALE_REG;
|
gfx_info.VI_Y_SCALE_REG = &VI_Y_SCALE_REG;
|
||||||
|
|
||||||
gfx_info.CheckInterrupts = dummy_check_interrupts;
|
gfx_info.CheckInterrupts = dummy_check_interrupts;
|
||||||
gfx_info.version = 2;
|
|
||||||
gfx_info.SP_STATUS_REG = &SP_STATUS_REG;
|
|
||||||
gfx_info.RDRAM_SIZE = &RDRAM_SIZE;
|
|
||||||
|
|
||||||
InitiateGFX(gfx_info);
|
InitiateGFX(gfx_info);
|
||||||
}
|
}
|
||||||
@ -112,3 +111,7 @@ void RT64UpdateScreen(uint32_t vi_origin) {
|
|||||||
|
|
||||||
UpdateScreen();
|
UpdateScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RT64ChangeWindow() {
|
||||||
|
ChangeWindow();
|
||||||
|
}
|
||||||
|
84
us.rev1.toml
Normal file
84
us.rev1.toml
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# Config file for Majora's Mask NTSC 1.0 Recompilation.
|
||||||
|
|
||||||
|
[input]
|
||||||
|
entrypoint = 0x80080000
|
||||||
|
# Paths are relative to the location of this config file.
|
||||||
|
elf_path = "mm.us.rev1.elf"
|
||||||
|
output_func_path = "RecompiledFuncs"
|
||||||
|
relocatable_sections_path = "overlays.us.rev1.txt"
|
||||||
|
|
||||||
|
[patches]
|
||||||
|
stubs = [
|
||||||
|
# Stub out unused functions that directly manipulate RCP status.
|
||||||
|
"func_80084940",
|
||||||
|
"func_80084968",
|
||||||
|
# Stub out an unnecessary function that accesses kseg1 addresses.
|
||||||
|
"func_800818F4"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Hooks
|
||||||
|
|
||||||
|
# Function definition for the overlay loading function.
|
||||||
|
[[patches.func]]
|
||||||
|
name = "load_overlays"
|
||||||
|
args = ["u32", "u32", "u32"]
|
||||||
|
|
||||||
|
# Function hooks for overlay loading.
|
||||||
|
[[patches.hook]]
|
||||||
|
func = "Idle_InitCodeAndMemory"
|
||||||
|
calls = "load_overlays"
|
||||||
|
args = ["a2", "a1", "a3"]
|
||||||
|
after_vram = 0x800802A4
|
||||||
|
|
||||||
|
[[patches.hook]]
|
||||||
|
func = "Load2_LoadOverlay"
|
||||||
|
calls = "load_overlays"
|
||||||
|
# args = [
|
||||||
|
# "a0", # $a0 contains rom start
|
||||||
|
# {operation = "load", type = "u32", base = "sp", offset = 0x10}, # sp + 10 contains the ram address
|
||||||
|
# {operation = "subtract", arguments = ["a1", "a0"]} # Calculate size from rom end - rom start
|
||||||
|
# ]
|
||||||
|
args = ["a1", "a0", "a2"]
|
||||||
|
# This vram address is an instruction in a delay slot. In that case, the recompiler will emit the
|
||||||
|
# hook call after this instruction is run and before the function is called.
|
||||||
|
after_vram = 0x80085048
|
||||||
|
|
||||||
|
# Single-instruction patches
|
||||||
|
|
||||||
|
# Write audio dlists to kseg0 (cached, 0x80...) addresses instead of kseg1 (uncached, 0xA0...) ones.
|
||||||
|
# This saves the recompiler from needing to handle checking for kseg1 addresses on every memory operation.
|
||||||
|
[[patches.instruction]]
|
||||||
|
func = "AudioHeap_WritebackDCache"
|
||||||
|
vram = 0x8018B510
|
||||||
|
value = 0x3C010000 # lui $at, 0x2000 -> lui $at, 0x0000
|
||||||
|
|
||||||
|
# These two may not be needed with RCP timeout detection disabled
|
||||||
|
# # Pretend the RSP has already halted so that the game doesn't attempt to directly manipulate RSP registers.
|
||||||
|
# [[patches.instruction]]
|
||||||
|
# func = "Sched_HandleAudioCancel"
|
||||||
|
# vram = 0x801763D8
|
||||||
|
# value = 0x240F0001 # lw $t7, 0x0($s1) -> li $t7, 1
|
||||||
|
|
||||||
|
# # Ditto.
|
||||||
|
# [[patches.instruction]]
|
||||||
|
# func = "Sched_HandleGfxCancel"
|
||||||
|
# vram = 0x80176534
|
||||||
|
# value = 0x240F0001 # lw $t7, 0x0($s1) -> li $t7, 1
|
||||||
|
|
||||||
|
# Disable RCP timeout detection (sometimes throws false positives, not needed)
|
||||||
|
[[patches.instruction]]
|
||||||
|
func = "AudioMgr_HandleRetrace"
|
||||||
|
vram = 0x80172DBC
|
||||||
|
value = 0x00000000 # jal osSetTimer -> nop
|
||||||
|
|
||||||
|
# Ditto.
|
||||||
|
[[patches.instruction]]
|
||||||
|
func = "Graph_TaskSet00"
|
||||||
|
vram = 0x80174218
|
||||||
|
value = 0x00000000 # jal osSetTimer -> nop
|
||||||
|
|
||||||
|
# Prevent the minimap from drawing at a point where it can cause a crash when pausing.
|
||||||
|
[[patches.instruction]]
|
||||||
|
func = "func_80106644"
|
||||||
|
vram = 0x80106684
|
||||||
|
value = 0x29E10003 # slti $at, $t7, 0x4 -> slti $at, $t7, 0x3
|
Loading…
Reference in New Issue
Block a user