You've already forked Microtransactions64
mirror of
https://github.com/Print-and-Panic/Microtransactions64.git
synced 2026-01-21 10:17:19 -08:00
Added emulator detection (#651)
* Added emulator detection * Fixed missing assignments * Disable interrupts around the count factor test * Added more comments to emutest * Changed PJ64 enum values so the versions work as a bitfield * Updated README * Fixed comments * Updated enum values so you can safely AND and OR all emulator version flags together * Remove redundant gIsConsole, gIsVC, and gCacheEmulated global variables * Changed console check to be more future proof against Ares * Use assembly file instead of casting to a function pointer * Moved round_double_to_float back to its own compilation unit * Moved the ParallelN64 check before the Ares check for better future-proofing * Align pj64_get_count_factor_asm with cache lines... not that it actually matters for pj64 * Adjusted some comments * Made emulator check thread-safe on emulators that emulate PI timings * Added gIsConsole macro for backwards compatibility * Added cen64 to INSTANT_INPUT_BLACKLIST * Updated comment
This commit is contained in:
@@ -27,9 +27,10 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin
|
|||||||
- **Kaze**: Graph node optimisations, automatic optimal collision distance
|
- **Kaze**: Graph node optimisations, automatic optimal collision distance
|
||||||
- **Pyro Jay**: Texture improvements, repo banner art, some QoL stuff
|
- **Pyro Jay**: Texture improvements, repo banner art, some QoL stuff
|
||||||
- **CrashOveride**: creating the [ultrasm64](https://github.com/CrashOveride95/ultrasm64) repo
|
- **CrashOveride**: creating the [ultrasm64](https://github.com/CrashOveride95/ultrasm64) repo
|
||||||
- **falcobuster**: Original coordinate overflow fix (world scale), ASM version of extended bounds
|
- **falcobuster**: Original coordinate overflow fix (world scale), ASM version of extended bounds, emulator detector
|
||||||
- **anonymous_moose**: porting falco's extended bounds to decomp
|
- **anonymous_moose**: porting falco's extended bounds to decomp
|
||||||
- **tuxlovesyou**: `LOAD_MIO0_TEXTURE` macro and moral support
|
- **tuxlovesyou**: `LOAD_MIO0_TEXTURE` macro and moral support
|
||||||
|
- **devwizard**: the PJ64 pre-v3.0 detection part of the emulator detector
|
||||||
|
|
||||||
Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
|
Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
|
|||||||
- Many general use defines for object struct members, meant for use in custom object behaviors. Check `include/object_fields.h` for more info on this. (By MrComit)
|
- Many general use defines for object struct members, meant for use in custom object behaviors. Check `include/object_fields.h` for more info on this. (By MrComit)
|
||||||
- Included `actors/group0.c` in `behavior_data.c`
|
- Included `actors/group0.c` in `behavior_data.c`
|
||||||
- The internal ROM name is now set with a define in `config/config_rom.h` to make it simpler
|
- The internal ROM name is now set with a define in `config/config_rom.h` to make it simpler
|
||||||
- There is a `gIsConsole` variable that is 1 when running on console and 0 when running on emulator. This way you can wrap your code in a console check.
|
- There is a `gEmulator` variable to detect console or specific emulators and emulator versions
|
||||||
- Expanded audio heap allows for a larger concurrent note count and the importing of more m64 sequences and sound banks (By ArcticJaguar725) *
|
- Expanded audio heap allows for a larger concurrent note count and the importing of more m64 sequences and sound banks (By ArcticJaguar725) *
|
||||||
- You can set a test level in `config/config_debug.h` in order to boot straight into it, so you can quickly test the level you're working on. *
|
- You can set a test level in `config/config_debug.h` in order to boot straight into it, so you can quickly test the level you're working on. *
|
||||||
- Allow all surfaces in the game to have a `force` parameter. Activating this doesn't REQUIRE you to set `force` for every surface: If you don't set, it will default to 0x0000 rather than crashing. Increases RAM usage of collision. *
|
- Allow all surfaces in the game to have a `force` parameter. Activating this doesn't REQUIRE you to set `force` for every surface: If you don't set, it will default to 0x0000 rather than crashing. Increases RAM usage of collision. *
|
||||||
@@ -105,7 +106,7 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
|
|||||||
|
|
||||||
**Neat Misc. Changes:**
|
**Neat Misc. Changes:**
|
||||||
- Instant Input patch by Wiseguy (Removes all input lag caused by plugins supporting framebuffer)
|
- Instant Input patch by Wiseguy (Removes all input lag caused by plugins supporting framebuffer)
|
||||||
- This means that you'll have to do your framebuffer effects on buffer 0 for emulator, but NOT for console. You can use the `gIsConsole` variable to check for console when doing your framebuffer effects.
|
- This means that you'll have to do your framebuffer effects on buffer 0 for emulator, but NOT for console. You can use the `gEmulator` variable to check for console when doing your framebuffer effects.
|
||||||
- Widescreen (16:9) support toggleable by pressing `L` in the pause menu. *
|
- Widescreen (16:9) support toggleable by pressing `L` in the pause menu. *
|
||||||
- S2DEX engine by someone2639! To use it, compile with `make TEXT_ENGINE=s2dex_text_engine` or just set `TEXT_ENGINE` to `s2dex_text_engine` in the makefile.
|
- S2DEX engine by someone2639! To use it, compile with `make TEXT_ENGINE=s2dex_text_engine` or just set `TEXT_ENGINE` to `s2dex_text_engine` in the makefile.
|
||||||
- ia8 (64x64) coins, the vanilla coin texture is upgraded to accomodate. *
|
- ia8 (64x64) coins, the vanilla coin texture is upgraded to accomodate. *
|
||||||
@@ -135,7 +136,7 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
|
|||||||
- It has been patched with someone2639's shiftable segments patch
|
- It has been patched with someone2639's shiftable segments patch
|
||||||
- Wiseguy's instant input patch has been added to allow for less input lag on emulation (Does not affect console)
|
- Wiseguy's instant input patch has been added to allow for less input lag on emulation (Does not affect console)
|
||||||
This does mean that any framebuffer effects will have to be done on buffer 0 if targeting emulators
|
This does mean that any framebuffer effects will have to be done on buffer 0 if targeting emulators
|
||||||
- Automatic console and emulator detection: Use the `gIsConsole` variable to wrap your code in an emulator check.
|
- Automatic console and emulator detection: Use the `gEmulator` variable to wrap your code in an emulator check.
|
||||||
- Separate defines for emulator and console black border height.
|
- Separate defines for emulator and console black border height.
|
||||||
- Getting HVQM FMV support to work with the game is WIP.
|
- Getting HVQM FMV support to work with the game is WIP.
|
||||||
|
|
||||||
|
|||||||
14
asm/pj64_get_count_factor_asm.s
Normal file
14
asm/pj64_get_count_factor_asm.s
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Used as part of emulator detection. The dynarec core of PJ64 4.0 only updates
|
||||||
|
// the COUNT register in between recompiled functions, so this will return 0 on
|
||||||
|
// PJ64 4.0 dynarec, but will instead return the count factor on other versions.
|
||||||
|
|
||||||
|
.include "macros.inc"
|
||||||
|
.section .text, "ax"
|
||||||
|
.set noreorder
|
||||||
|
|
||||||
|
.balign 32
|
||||||
|
glabel pj64_get_count_factor_asm
|
||||||
|
mfc0 $t0, $9 // $9 is the COUNT register
|
||||||
|
mfc0 $t1, $9
|
||||||
|
jr $ra
|
||||||
|
subu $v0, $t1, $t0
|
||||||
@@ -336,7 +336,6 @@ index ad9fdb7d..26e1f000 100644
|
|||||||
@@ -29,6 +29,9 @@
|
@@ -29,6 +29,9 @@
|
||||||
#include "puppycam2.h"
|
#include "puppycam2.h"
|
||||||
#include "debug_box.h"
|
#include "debug_box.h"
|
||||||
#include "vc_check.h"
|
|
||||||
+#ifdef REONUCAM
|
+#ifdef REONUCAM
|
||||||
+#include "camera.h"
|
+#include "camera.h"
|
||||||
+#endif
|
+#endif
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
/**
|
/**
|
||||||
* When this option is enabled, LODs will ONLY work on console.
|
* When this option is enabled, LODs will ONLY work on console.
|
||||||
* When this option is disabled, LODs will work regardless of whether console or emulator is used.
|
* When this option is disabled, LODs will work regardless of whether console or emulator is used.
|
||||||
* Regardless of whether this setting is enabled or not, you can use gIsConsole to wrap your own code in a console check.
|
* Regardless of whether this setting is enabled or not, you can use gEmulator to wrap your own code in a console check.
|
||||||
*/
|
*/
|
||||||
#define AUTO_LOD
|
#define AUTO_LOD
|
||||||
|
|
||||||
|
|||||||
1
sm64.ld
1
sm64.ld
@@ -160,6 +160,7 @@ SECTIONS
|
|||||||
#ifdef EEP
|
#ifdef EEP
|
||||||
KEEP(BUILD_DIR/asm/vc_bin.o(.text*));
|
KEEP(BUILD_DIR/asm/vc_bin.o(.text*));
|
||||||
#endif
|
#endif
|
||||||
|
KEEP(BUILD_DIR/asm/pj64_get_count_factor_asm.o(.text*));
|
||||||
KEEP(BUILD_DIR/asm/round.o(.text*));
|
KEEP(BUILD_DIR/asm/round.o(.text*));
|
||||||
|
|
||||||
BUILD_DIR/src/boot*.o(.text*);
|
BUILD_DIR/src/boot*.o(.text*);
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
#include "synthesis.h"
|
#include "synthesis.h"
|
||||||
#include "seqplayer.h"
|
#include "seqplayer.h"
|
||||||
#include "effects.h"
|
#include "effects.h"
|
||||||
#include "game/game_init.h"
|
#include "game/emutest.h"
|
||||||
#include "game/puppyprint.h"
|
#include "game/puppyprint.h"
|
||||||
#include "game/vc_check.h"
|
|
||||||
#include "game/debug.h"
|
#include "game/debug.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
@@ -1171,7 +1170,7 @@ void audio_reset_session(s32 reverbPresetId) {
|
|||||||
if (gAudioLoadLock != AUDIO_LOCK_UNINITIALIZED) {
|
if (gAudioLoadLock != AUDIO_LOCK_UNINITIALIZED) {
|
||||||
gAudioLoadLock = AUDIO_LOCK_LOADING;
|
gAudioLoadLock = AUDIO_LOCK_LOADING;
|
||||||
|
|
||||||
if (!gIsVC) {
|
if (!(gEmulator & EMU_WIIVC)) {
|
||||||
gAudioFrameCount = 0;
|
gAudioFrameCount = 0;
|
||||||
while (gAudioFrameCount < 1) {
|
while (gAudioFrameCount < 1) {
|
||||||
// spin
|
// spin
|
||||||
@@ -1325,7 +1324,7 @@ void audio_reset_session(void) {
|
|||||||
gAudioBufferParameters.minAiBufferLength *= gAudioBufferParameters.presetUnk4;
|
gAudioBufferParameters.minAiBufferLength *= gAudioBufferParameters.presetUnk4;
|
||||||
gAudioBufferParameters.updatesPerFrame *= gAudioBufferParameters.presetUnk4;
|
gAudioBufferParameters.updatesPerFrame *= gAudioBufferParameters.presetUnk4;
|
||||||
|
|
||||||
if (gIsConsole)
|
if (gEmulator & EMU_CONSOLE)
|
||||||
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_CONSOLE;
|
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_CONSOLE;
|
||||||
else
|
else
|
||||||
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_EMULATOR;
|
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_EMULATOR;
|
||||||
@@ -1352,7 +1351,7 @@ void audio_reset_session(void) {
|
|||||||
gMinAiBufferLength = gSamplesPerFrameTarget - 0x10;
|
gMinAiBufferLength = gSamplesPerFrameTarget - 0x10;
|
||||||
gAudioUpdatesPerFrame = updatesPerFrame = gSamplesPerFrameTarget / 160 + 1;
|
gAudioUpdatesPerFrame = updatesPerFrame = gSamplesPerFrameTarget / 160 + 1;
|
||||||
|
|
||||||
if (gIsConsole)
|
if (gEmulator & EMU_CONSOLE)
|
||||||
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_CONSOLE;
|
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_CONSOLE;
|
||||||
else
|
else
|
||||||
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_EMULATOR;
|
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_EMULATOR;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "game/main.h"
|
#include "game/main.h"
|
||||||
#include "game/rumble_init.h"
|
#include "game/rumble_init.h"
|
||||||
#include "game/version.h"
|
#include "game/version.h"
|
||||||
#include "game/vc_check.h"
|
|
||||||
#ifdef UNF
|
#ifdef UNF
|
||||||
#include "usb/usb.h"
|
#include "usb/usb.h"
|
||||||
#include "usb/debug.h"
|
#include "usb/debug.h"
|
||||||
@@ -23,8 +22,7 @@
|
|||||||
#include "game/puppyprint.h"
|
#include "game/puppyprint.h"
|
||||||
#include "game/puppylights.h"
|
#include "game/puppylights.h"
|
||||||
#include "game/profiling.h"
|
#include "game/profiling.h"
|
||||||
|
#include "game/emutest.h"
|
||||||
#include "game/vc_check.h"
|
|
||||||
|
|
||||||
// Message IDs
|
// Message IDs
|
||||||
enum MessageIDs {
|
enum MessageIDs {
|
||||||
@@ -318,21 +316,6 @@ void alert_rcp_hung_up(void) {
|
|||||||
error("RCP is HUNG UP!! Oh! MY GOD!!");
|
error("RCP is HUNG UP!! Oh! MY GOD!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_cache_emulation() {
|
|
||||||
// Disable interrupts to ensure that nothing evicts the variable from cache while we're using it.
|
|
||||||
u32 saved = __osDisableInt();
|
|
||||||
// Create a variable with an initial value of 1. This value will remain cached.
|
|
||||||
volatile u8 sCachedValue = 1;
|
|
||||||
// Overwrite the variable directly in RDRAM without going through cache.
|
|
||||||
// This should preserve its value of 1 in dcache if dcache is emulated correctly.
|
|
||||||
*(u8*)(K0_TO_K1(&sCachedValue)) = 0;
|
|
||||||
// Read the variable back from dcache, if it's still 1 then cache is emulated correctly.
|
|
||||||
// If it's zero, then dcache is not emulated correctly.
|
|
||||||
gCacheEmulated = sCachedValue;
|
|
||||||
// Restore interrupts
|
|
||||||
__osRestoreInt(saved);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the first and last values of the stack.
|
* Increment the first and last values of the stack.
|
||||||
* If they're different, that means an error has occured, so trigger a crash.
|
* If they're different, that means an error has occured, so trigger a crash.
|
||||||
@@ -366,7 +349,7 @@ void thread3_main(UNUSED void *arg) {
|
|||||||
setup_mesg_queues();
|
setup_mesg_queues();
|
||||||
alloc_pool();
|
alloc_pool();
|
||||||
load_engine_code_segment();
|
load_engine_code_segment();
|
||||||
gIsVC = IS_VC();
|
detect_emulator();
|
||||||
#ifndef UNF
|
#ifndef UNF
|
||||||
crash_screen_init();
|
crash_screen_init();
|
||||||
#endif
|
#endif
|
||||||
@@ -384,14 +367,8 @@ void thread3_main(UNUSED void *arg) {
|
|||||||
osSyncPrintf("Linker : %s\n", __linker__);
|
osSyncPrintf("Linker : %s\n", __linker__);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (IO_READ(DPC_CLOCK_REG) == 0) {
|
if (!(gEmulator & EMU_CONSOLE)) {
|
||||||
gIsConsole = FALSE;
|
|
||||||
gBorderHeight = BORDER_HEIGHT_EMULATOR;
|
gBorderHeight = BORDER_HEIGHT_EMULATOR;
|
||||||
if (!gIsVC) {
|
|
||||||
check_cache_emulation();
|
|
||||||
} else {
|
|
||||||
gCacheEmulated = FALSE;
|
|
||||||
}
|
|
||||||
#ifdef RCVI_HACK
|
#ifdef RCVI_HACK
|
||||||
VI.comRegs.vSync = 525*20;
|
VI.comRegs.vSync = 525*20;
|
||||||
change_vi(&VI, SCREEN_WIDTH, SCREEN_HEIGHT);
|
change_vi(&VI, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
@@ -400,7 +377,6 @@ void thread3_main(UNUSED void *arg) {
|
|||||||
osViSetSpecialFeatures(OS_VI_GAMMA_OFF);
|
osViSetSpecialFeatures(OS_VI_GAMMA_OFF);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
gIsConsole = TRUE;
|
|
||||||
gBorderHeight = BORDER_HEIGHT_CONSOLE;
|
gBorderHeight = BORDER_HEIGHT_CONSOLE;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "game/puppycam2.h"
|
#include "game/puppycam2.h"
|
||||||
#include "game/puppyprint.h"
|
#include "game/puppyprint.h"
|
||||||
#include "game/puppylights.h"
|
#include "game/puppylights.h"
|
||||||
|
#include "game/emutest.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -740,7 +741,7 @@ static void level_cmd_set_music(void) {
|
|||||||
if (sCurrAreaIndex != -1) {
|
if (sCurrAreaIndex != -1) {
|
||||||
gAreas[sCurrAreaIndex].musicParam = CMD_GET(s16, 2);
|
gAreas[sCurrAreaIndex].musicParam = CMD_GET(s16, 2);
|
||||||
#ifdef BETTER_REVERB
|
#ifdef BETTER_REVERB
|
||||||
if (gIsConsole)
|
if (gEmulator & EMU_CONSOLE)
|
||||||
gAreas[sCurrAreaIndex].betterReverbPreset = CMD_GET(u8, 4);
|
gAreas[sCurrAreaIndex].betterReverbPreset = CMD_GET(u8, 4);
|
||||||
else
|
else
|
||||||
gAreas[sCurrAreaIndex].betterReverbPreset = CMD_GET(u8, 5);
|
gAreas[sCurrAreaIndex].betterReverbPreset = CMD_GET(u8, 5);
|
||||||
@@ -753,7 +754,7 @@ static void level_cmd_set_music(void) {
|
|||||||
static void level_cmd_set_menu_music(void) {
|
static void level_cmd_set_menu_music(void) {
|
||||||
#ifdef BETTER_REVERB
|
#ifdef BETTER_REVERB
|
||||||
// Must come before set_background_music()
|
// Must come before set_background_music()
|
||||||
if (gIsConsole)
|
if (gEmulator & EMU_CONSOLE)
|
||||||
gBetterReverbPresetValue = CMD_GET(u8, 4);
|
gBetterReverbPresetValue = CMD_GET(u8, 4);
|
||||||
else
|
else
|
||||||
gBetterReverbPresetValue = CMD_GET(u8, 5);
|
gBetterReverbPresetValue = CMD_GET(u8, 5);
|
||||||
@@ -907,7 +908,7 @@ static void level_cmd_puppylight_node(void) {
|
|||||||
static void level_cmd_set_echo(void) {
|
static void level_cmd_set_echo(void) {
|
||||||
if (sCurrAreaIndex >= 0 && sCurrAreaIndex < AREA_COUNT) {
|
if (sCurrAreaIndex >= 0 && sCurrAreaIndex < AREA_COUNT) {
|
||||||
gAreaData[sCurrAreaIndex].useEchoOverride = TRUE;
|
gAreaData[sCurrAreaIndex].useEchoOverride = TRUE;
|
||||||
if (gIsConsole)
|
if (gEmulator & EMU_CONSOLE)
|
||||||
gAreaData[sCurrAreaIndex].echoOverride = CMD_GET(s8, 2);
|
gAreaData[sCurrAreaIndex].echoOverride = CMD_GET(s8, 2);
|
||||||
else
|
else
|
||||||
gAreaData[sCurrAreaIndex].echoOverride = CMD_GET(s8, 3);
|
gAreaData[sCurrAreaIndex].echoOverride = CMD_GET(s8, 3);
|
||||||
|
|||||||
167
src/game/emutest.c
Normal file
167
src/game/emutest.c
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
#include "emutest.h"
|
||||||
|
|
||||||
|
#include <PR/os_internal_reg.h>
|
||||||
|
#include <PR/os_internal_si.h>
|
||||||
|
#include <PR/os_message.h>
|
||||||
|
#include <PR/os_pi.h>
|
||||||
|
#include <PR/R4300.h>
|
||||||
|
#include <ultra64.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "emutest_vc.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
extern OSMesgQueue gSIEventMesgQueue;
|
||||||
|
extern u8 __osContPifRam[];
|
||||||
|
extern u8 __osContLastCmd;
|
||||||
|
extern void __osSiGetAccess(void);
|
||||||
|
extern void __osSiRelAccess(void);
|
||||||
|
extern void __osPiGetAccess(void);
|
||||||
|
extern void __osPiRelAccess(void);
|
||||||
|
|
||||||
|
enum Emulator gEmulator = EMU_CONSOLE;
|
||||||
|
|
||||||
|
u32 pj64_get_count_factor_asm(void); // defined in asm/pj64_get_count_factor_asm.s
|
||||||
|
|
||||||
|
static inline u32 check_count_factor() {
|
||||||
|
const u32 saved = __osDisableInt();
|
||||||
|
const u32 cf = pj64_get_count_factor_asm();
|
||||||
|
__osRestoreInt(saved);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum Emulator get_pj64_version() {
|
||||||
|
// When calling this function, we know that the emulator is some version of Project 64,
|
||||||
|
// and it isn't using the PJ64 4.0 interpreter core. Figure out which version it is.
|
||||||
|
|
||||||
|
// PJ64 4.0 dynarec core doesn't update the COUNT register correctly within recompiled functions
|
||||||
|
if (check_count_factor() == 0) {
|
||||||
|
return EMU_PROJECT64_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instead of implementing this PIF command correctly, PJ64 versions prior to 3.0 just have
|
||||||
|
// a set of hardcoded values for some requests. At least one of these hardcoded values has a
|
||||||
|
// typo in it, making it give an incorrect result.
|
||||||
|
__osSiGetAccess();
|
||||||
|
u32 *pifRam32 = (u32*)__osContPifRam;
|
||||||
|
for (s32 i = 0; i < 15; i++) pifRam32[i] = 0;
|
||||||
|
pifRam32[15] = 2;
|
||||||
|
|
||||||
|
const u8 cicTest[] = {
|
||||||
|
0x0F, 0x0F,
|
||||||
|
0xEC, 0x3C, 0xB6, 0x76, 0xB8, 0x1D, 0xBB, 0x8F,
|
||||||
|
0x6B, 0x3A, 0x80, 0xEC, 0xED, 0xEA, 0x5B
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(&__osContPifRam[46], cicTest, 17);
|
||||||
|
|
||||||
|
__osSiRawStartDma(OS_WRITE, __osContPifRam);
|
||||||
|
osRecvMesg(&gSIEventMesgQueue, NULL, OS_MESG_BLOCK);
|
||||||
|
__osContLastCmd = 254;
|
||||||
|
|
||||||
|
__osSiRawStartDma(OS_READ, __osContPifRam);
|
||||||
|
osRecvMesg(&gSIEventMesgQueue, NULL, OS_MESG_BLOCK);
|
||||||
|
const u8 pifCheck = __osContPifRam[54];
|
||||||
|
__osSiRelAccess();
|
||||||
|
|
||||||
|
// check for the typo'd byte
|
||||||
|
return (pifCheck == 0xB0) ? EMU_PROJECT64_1_OR_2 : EMU_PROJECT64_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 check_cache_emulation() {
|
||||||
|
// Disable interrupts to ensure that nothing evicts the variable from cache while we're using it.
|
||||||
|
u32 saved = __osDisableInt();
|
||||||
|
// Create a variable with an initial value of 1. This value will remain cached.
|
||||||
|
volatile u8 sCachedValue = 1;
|
||||||
|
// Overwrite the variable directly in RDRAM without going through cache.
|
||||||
|
// This should preserve its value of 1 in dcache if dcache is emulated correctly.
|
||||||
|
*(u8*)(K0_TO_K1(&sCachedValue)) = 0;
|
||||||
|
// Read the variable back from dcache, if it's still 1 then cache is emulated correctly.
|
||||||
|
// If it's zero, then dcache is not emulated correctly.
|
||||||
|
const u8 cacheEmulated = sCachedValue;
|
||||||
|
// Restore interrupts
|
||||||
|
__osRestoreInt(saved);
|
||||||
|
return cacheEmulated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void detect_emulator() {
|
||||||
|
if ((u32)IO_READ(DPC_PIPEBUSY_REG) | (u32)IO_READ(DPC_TMEM_REG) | (u32)IO_READ(DPC_BUFBUSY_REG)) {
|
||||||
|
gEmulator = EMU_CONSOLE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This check forces RTZ bug on vc
|
||||||
|
* If console is N64/adequate Emu round-to-nearest (RTN) rounding mode is used
|
||||||
|
* If console is VC round-to-zero (RTZ) mode is used
|
||||||
|
*
|
||||||
|
* The double value 0.9999999999999999 used is 0x3FEFFFFFFFFFFFFF in binary
|
||||||
|
* Exponent=01111111110, Mantissa=1111111111111111111111111111111111111111111111111111
|
||||||
|
* RTZ will output not 1.0f, RTN will output exactly 1.0f
|
||||||
|
*/
|
||||||
|
if (1.0f != round_double_to_float(0.9999999999999999)) {
|
||||||
|
gEmulator = EMU_WIIVC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a read from unmapped PIF ram.
|
||||||
|
// On console and well behaved emulators, this echos back the lower half of
|
||||||
|
// the requested memory address, repeating it if a whole word is requested.
|
||||||
|
// So in this case, it should result in 0x01040104
|
||||||
|
u32 magic;
|
||||||
|
osPiReadIo(0x1fd00104u, &magic);
|
||||||
|
if (magic == 0u) {
|
||||||
|
// Older versions of mupen (and pre-2.12 ParallelN64) just always read 0
|
||||||
|
gEmulator = EMU_MUPEN_OLD;
|
||||||
|
return;
|
||||||
|
} else if (magic != 0x01040104u) {
|
||||||
|
// cen64 does... something. The result is consistent, but not what it should be
|
||||||
|
gEmulator = EMU_CEN64;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__osPiGetAccess();
|
||||||
|
while (IO_READ(PI_STATUS_REG) & (PI_STATUS_DMA_BUSY|PI_STATUS_IO_BUSY));
|
||||||
|
const u16 halfMagic = *((volatile u16*)0xbfd00106u);
|
||||||
|
__osPiRelAccess();
|
||||||
|
|
||||||
|
// Now do a halfword read instead.
|
||||||
|
switch (halfMagic) {
|
||||||
|
// This is the correct result (echo back the lower half of the requested address)
|
||||||
|
case 0x0106: {
|
||||||
|
// Test to see if the libpl emulator extension is present.
|
||||||
|
osPiWriteIo(0x1ffb0000u, 0u);
|
||||||
|
osPiReadIo(0x1ffb0000u, &magic);
|
||||||
|
if (magic == 0x00500000u) {
|
||||||
|
// libpl is supported. Must be ParallelN64
|
||||||
|
gEmulator = EMU_PARALLELN64;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the cache is emulated, it's Ares
|
||||||
|
if (check_cache_emulation()) {
|
||||||
|
gEmulator = EMU_ARES;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// its the Project64 4.0 interpreter core
|
||||||
|
gEmulator = EMU_PROJECT64_4;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// This looks like it should be the expected result considering what we got when we
|
||||||
|
// requested the whole word, but that's actually wrong. Later versions of mupen
|
||||||
|
// (and the Simple64 fork of it) get this wrong.
|
||||||
|
case 0x0104:
|
||||||
|
gEmulator = check_cache_emulation() ? EMU_SIMPLE64 : EMU_MUPEN64PLUS_NEXT;
|
||||||
|
return;
|
||||||
|
// If reading a word gives the correct response, but reading a halfword always gives 0,
|
||||||
|
// then we are dealing with some version of Project 64. Call into this helper function
|
||||||
|
// to find out which version we're dealing with.
|
||||||
|
case 0x0000:
|
||||||
|
gEmulator = get_pj64_version();
|
||||||
|
return;
|
||||||
|
// No known emulator gives any other value. If we somehow manage to get here, just return 0
|
||||||
|
default:
|
||||||
|
gEmulator = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/game/emutest.h
Normal file
43
src/game/emutest.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef EMUTEST_H
|
||||||
|
#define EMUTEST_H
|
||||||
|
|
||||||
|
enum Emulator {
|
||||||
|
EMU_WIIVC = 0x0001,
|
||||||
|
EMU_PROJECT64_ANY = 0x001E,
|
||||||
|
EMU_PROJECT64_1_OR_2 = 0x0006, // PJ64 1.6 or similar (up to 2.3)
|
||||||
|
EMU_PROJECT64_3 = 0x0008, // PJ64 3.X
|
||||||
|
EMU_PROJECT64_4 = 0x0010, // PJ64 4.0 or later
|
||||||
|
EMU_MUPEN_BASED = 0x0060, // mupen64plus or pre-2.12 paralleln64, but NOT simple64 or new paralleln64
|
||||||
|
EMU_MUPEN_OLD = 0x0020, // Nemu64 and pre-2.12 paralleln64 will also get detected as this
|
||||||
|
EMU_MUPEN64PLUS_NEXT = 0x040,
|
||||||
|
EMU_CEN64 = 0x0080,
|
||||||
|
EMU_SIMPLE64 = 0x0100,
|
||||||
|
EMU_PARALLELN64 = 0x0200, // ParallelN64 2.12 or later
|
||||||
|
EMU_ARES = 0x0400,
|
||||||
|
EMU_CONSOLE = 0x0800
|
||||||
|
};
|
||||||
|
|
||||||
|
// initializes gEmulator
|
||||||
|
extern void detect_emulator();
|
||||||
|
|
||||||
|
/* gEmulator is an enum that identifies the current emulator.
|
||||||
|
* The enum values work as a bitfield, so you can use the & and | operators
|
||||||
|
* to test for multiple emulators or versions at once.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* Test for any version of PJ64:
|
||||||
|
* if (gEmulator & EMU_PROJECT64_ANY)
|
||||||
|
*
|
||||||
|
* Test for only PJ64 < 3.0:
|
||||||
|
* if (gEmulator & EMU_PROJECT64_1_OR_2)
|
||||||
|
*
|
||||||
|
* Test for Console, Ares, or ParallelN64:
|
||||||
|
* if (gEmulator & (EMU_CONSOLE | EMU_ARES | EMU_PARALLELN64))
|
||||||
|
*/
|
||||||
|
extern enum Emulator gEmulator;
|
||||||
|
|
||||||
|
// Included for backwards compatibility when upgrading from HackerSM64 2.0
|
||||||
|
#define gIsConsole ((gEmulator & EMU_CONSOLE) != 0)
|
||||||
|
|
||||||
|
#endif
|
||||||
5
src/game/emutest_vc.c
Normal file
5
src/game/emutest_vc.c
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include "emutest_vc.h"
|
||||||
|
|
||||||
|
f32 round_double_to_float(f64 v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
9
src/game/emutest_vc.h
Normal file
9
src/game/emutest_vc.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef EMUTEST_VC_H
|
||||||
|
#define EMUTEST_VC_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
__attribute__((externally_visible))
|
||||||
|
extern f32 round_double_to_float(f64 v);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -28,9 +28,12 @@
|
|||||||
#include "puppyprint.h"
|
#include "puppyprint.h"
|
||||||
#include "puppycam2.h"
|
#include "puppycam2.h"
|
||||||
#include "debug_box.h"
|
#include "debug_box.h"
|
||||||
#include "vc_check.h"
|
|
||||||
#include "vc_ultra.h"
|
#include "vc_ultra.h"
|
||||||
#include "profiling.h"
|
#include "profiling.h"
|
||||||
|
#include "emutest.h"
|
||||||
|
|
||||||
|
// Emulators that the Instant Input patch should not be applied to
|
||||||
|
#define INSTANT_INPUT_BLACKLIST (EMU_CONSOLE | EMU_WIIVC | EMU_ARES | EMU_SIMPLE64 | EMU_CEN64)
|
||||||
|
|
||||||
// First 3 controller slots
|
// First 3 controller slots
|
||||||
struct Controller gControllers[3];
|
struct Controller gControllers[3];
|
||||||
@@ -46,8 +49,6 @@ OSContStatus gControllerStatuses[4];
|
|||||||
OSContPadEx gControllerPads[4];
|
OSContPadEx gControllerPads[4];
|
||||||
u8 gControllerBits;
|
u8 gControllerBits;
|
||||||
s8 gGamecubeControllerPort = -1; // HackerSM64: This is set to -1 if there's no GC controller, 0 if there's one in the first port and 1 if there's one in the second port.
|
s8 gGamecubeControllerPort = -1; // HackerSM64: This is set to -1 if there's no GC controller, 0 if there's one in the first port and 1 if there's one in the second port.
|
||||||
u8 gIsConsole = TRUE; // Needs to be initialized before audio_reset_session is called
|
|
||||||
u8 gCacheEmulated = TRUE;
|
|
||||||
u8 gBorderHeight;
|
u8 gBorderHeight;
|
||||||
#ifdef VANILLA_STYLE_CUSTOM_DEBUG
|
#ifdef VANILLA_STYLE_CUSTOM_DEBUG
|
||||||
u8 gCustomDebugMode;
|
u8 gCustomDebugMode;
|
||||||
@@ -404,8 +405,8 @@ void render_init(void) {
|
|||||||
|
|
||||||
// Skip incrementing the initial framebuffer index on emulators so that they display immediately as the Gfx task finishes
|
// Skip incrementing the initial framebuffer index on emulators so that they display immediately as the Gfx task finishes
|
||||||
// VC probably emulates osViSwapBuffer accurately so instant patch breaks VC compatibility
|
// VC probably emulates osViSwapBuffer accurately so instant patch breaks VC compatibility
|
||||||
// Currently, Ares passes the cache emulation test and has issues with single buffering so disable it there as well.
|
// Currently, Ares and Simple64 have issues with single buffering so disable it there as well.
|
||||||
if (gIsConsole || gIsVC || gCacheEmulated) {
|
if (gEmulator & INSTANT_INPUT_BLACKLIST) {
|
||||||
sRenderingFramebuffer++;
|
sRenderingFramebuffer++;
|
||||||
}
|
}
|
||||||
gGlobalTimer++;
|
gGlobalTimer++;
|
||||||
@@ -444,7 +445,7 @@ void display_and_vsync(void) {
|
|||||||
osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
|
osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
|
||||||
#endif
|
#endif
|
||||||
// Skip swapping buffers on inaccurate emulators other than VC so that they display immediately as the Gfx task finishes
|
// Skip swapping buffers on inaccurate emulators other than VC so that they display immediately as the Gfx task finishes
|
||||||
if (gIsConsole || gIsVC || gCacheEmulated) {
|
if (gEmulator & INSTANT_INPUT_BLACKLIST) {
|
||||||
if (++sRenderedFramebuffer == 3) {
|
if (++sRenderedFramebuffer == 3) {
|
||||||
sRenderedFramebuffer = 0;
|
sRenderedFramebuffer = 0;
|
||||||
}
|
}
|
||||||
@@ -610,7 +611,7 @@ void read_controller_inputs(s32 threadID) {
|
|||||||
// if we're receiving inputs, update the controller struct with the new button info.
|
// if we're receiving inputs, update the controller struct with the new button info.
|
||||||
if (controller->controllerData != NULL) {
|
if (controller->controllerData != NULL) {
|
||||||
// HackerSM64: Swaps Z and L, only on console, and only when playing with a GameCube controller.
|
// HackerSM64: Swaps Z and L, only on console, and only when playing with a GameCube controller.
|
||||||
if (gIsConsole && i == gGamecubeControllerPort) {
|
if ((gEmulator & EMU_CONSOLE) && i == gGamecubeControllerPort) {
|
||||||
u32 oldButton = controller->controllerData->button;
|
u32 oldButton = controller->controllerData->button;
|
||||||
u32 newButton = oldButton & ~(Z_TRIG | L_TRIG);
|
u32 newButton = oldButton & ~(Z_TRIG | L_TRIG);
|
||||||
if (oldButton & Z_TRIG) {
|
if (oldButton & Z_TRIG) {
|
||||||
@@ -668,7 +669,7 @@ void init_controllers(void) {
|
|||||||
#ifdef EEP
|
#ifdef EEP
|
||||||
// strangely enough, the EEPROM probe for save data is done in this function.
|
// strangely enough, the EEPROM probe for save data is done in this function.
|
||||||
// save pak detection?
|
// save pak detection?
|
||||||
gEepromProbe = gIsVC
|
gEepromProbe = (gEmulator & EMU_WIIVC)
|
||||||
? osEepromProbeVC(&gSIEventMesgQueue)
|
? osEepromProbeVC(&gSIEventMesgQueue)
|
||||||
: osEepromProbe (&gSIEventMesgQueue);
|
: osEepromProbe (&gSIEventMesgQueue);
|
||||||
#endif
|
#endif
|
||||||
@@ -695,7 +696,7 @@ void init_controllers(void) {
|
|||||||
gControllers[cont++].controllerData = &gControllerPads[port];
|
gControllers[cont++].controllerData = &gControllerPads[port];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((__osControllerTypes[1] == CONT_TYPE_GCN) && (gIsConsole)) {
|
if ((__osControllerTypes[1] == CONT_TYPE_GCN) && (gEmulator & EMU_CONSOLE)) {
|
||||||
gGamecubeControllerPort = 1;
|
gGamecubeControllerPort = 1;
|
||||||
gPlayer1Controller = &gControllers[1];
|
gPlayer1Controller = &gControllers[1];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ extern u8 *gGfxPoolEnd;
|
|||||||
extern struct GfxPool *gGfxPool;
|
extern struct GfxPool *gGfxPool;
|
||||||
extern u8 gControllerBits;
|
extern u8 gControllerBits;
|
||||||
extern s8 gGamecubeControllerPort;
|
extern s8 gGamecubeControllerPort;
|
||||||
extern u8 gIsConsole;
|
|
||||||
extern u8 gCacheEmulated;
|
|
||||||
extern u8 gBorderHeight;
|
extern u8 gBorderHeight;
|
||||||
#ifdef VANILLA_STYLE_CUSTOM_DEBUG
|
#ifdef VANILLA_STYLE_CUSTOM_DEBUG
|
||||||
extern u8 gCustomDebugMode;
|
extern u8 gCustomDebugMode;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "save_file.h"
|
#include "save_file.h"
|
||||||
#include "sound_init.h"
|
#include "sound_init.h"
|
||||||
#include "rumble_init.h"
|
#include "rumble_init.h"
|
||||||
|
#include "emutest.h"
|
||||||
|
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
@@ -1874,7 +1875,7 @@ void init_mario_from_save_file(void) {
|
|||||||
gMarioState->statusForCamera = &gPlayerCameraState[0];
|
gMarioState->statusForCamera = &gPlayerCameraState[0];
|
||||||
gMarioState->marioBodyState = &gBodyStates[0];
|
gMarioState->marioBodyState = &gBodyStates[0];
|
||||||
gMarioState->animList = &gMarioAnimsBuf;
|
gMarioState->animList = &gMarioAnimsBuf;
|
||||||
if (gIsConsole && __osControllerTypes[1] == CONT_TYPE_GCN) {
|
if ((gEmulator & EMU_CONSOLE) && __osControllerTypes[1] == CONT_TYPE_GCN) {
|
||||||
gMarioState->controller = &gControllers[1];
|
gMarioState->controller = &gControllers[1];
|
||||||
} else {
|
} else {
|
||||||
gMarioState->controller = &gControllers[0];
|
gMarioState->controller = &gControllers[0];
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "behavior_data.h"
|
#include "behavior_data.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "color_presets.h"
|
#include "color_presets.h"
|
||||||
|
#include "emutest.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "config/config_world.h"
|
#include "config/config_world.h"
|
||||||
@@ -314,7 +315,7 @@ void switch_ucode(s32 ucode) {
|
|||||||
break;
|
break;
|
||||||
case GRAPH_NODE_UCODE_REJ:
|
case GRAPH_NODE_UCODE_REJ:
|
||||||
// Use .rej Microcode, skip sub-pixel processing on console
|
// Use .rej Microcode, skip sub-pixel processing on console
|
||||||
if (gIsConsole) {
|
if (gEmulator & EMU_CONSOLE) {
|
||||||
gSPLoadUcodeL(gDisplayListHead++, gspF3DLX2_Rej_fifo); // F3DLX2_Rej
|
gSPLoadUcodeL(gDisplayListHead++, gspF3DLX2_Rej_fifo); // F3DLX2_Rej
|
||||||
} else {
|
} else {
|
||||||
gSPLoadUcodeL(gDisplayListHead++, gspF3DEX2_Rej_fifo); // F3DEX2_Rej
|
gSPLoadUcodeL(gDisplayListHead++, gspF3DEX2_Rej_fifo); // F3DEX2_Rej
|
||||||
@@ -583,7 +584,7 @@ void geo_process_perspective(struct GraphNodePerspective *node) {
|
|||||||
// If an emulator is detected, use a large value for the half fov
|
// If an emulator is detected, use a large value for the half fov
|
||||||
// horizontal value to account for viewport widescreen hacks.
|
// horizontal value to account for viewport widescreen hacks.
|
||||||
|
|
||||||
if(!gIsConsole){
|
if(!(gEmulator & EMU_CONSOLE)){
|
||||||
node->halfFovHorizontal = 9999.0f;
|
node->halfFovHorizontal = 9999.0f;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -614,7 +615,7 @@ static f32 get_dist_from_camera(Vec3f pos) {
|
|||||||
*/
|
*/
|
||||||
void geo_process_level_of_detail(struct GraphNodeLevelOfDetail *node) {
|
void geo_process_level_of_detail(struct GraphNodeLevelOfDetail *node) {
|
||||||
#ifdef AUTO_LOD
|
#ifdef AUTO_LOD
|
||||||
f32 distanceFromCam = gIsConsole ? get_dist_from_camera(gMatStack[gMatStackIndex][3]) : 50.0f;
|
f32 distanceFromCam = (gEmulator & EMU_CONSOLE) ? get_dist_from_camera(gMatStack[gMatStackIndex][3]) : 50.0f;
|
||||||
#else
|
#else
|
||||||
f32 distanceFromCam = get_dist_from_camera(gMatStack[gMatStackIndex][3]);
|
f32 distanceFromCam = get_dist_from_camera(gMatStack[gMatStackIndex][3]);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "level_commands.h"
|
#include "level_commands.h"
|
||||||
#include "rumble_init.h"
|
#include "rumble_init.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "emutest.h"
|
||||||
#ifdef SRAM
|
#ifdef SRAM
|
||||||
#include "sram.h"
|
#include "sram.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -55,7 +56,6 @@ s8 gLevelToCourseNumTable[] = {
|
|||||||
STATIC_ASSERT(ARRAY_COUNT(gLevelToCourseNumTable) == LEVEL_COUNT - 1,
|
STATIC_ASSERT(ARRAY_COUNT(gLevelToCourseNumTable) == LEVEL_COUNT - 1,
|
||||||
"change this array if you are adding levels");
|
"change this array if you are adding levels");
|
||||||
#ifdef EEP
|
#ifdef EEP
|
||||||
#include "vc_check.h"
|
|
||||||
#include "vc_ultra.h"
|
#include "vc_ultra.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +76,7 @@ static s32 read_eeprom_data(void *buffer, s32 size) {
|
|||||||
block_until_rumble_pak_free();
|
block_until_rumble_pak_free();
|
||||||
#endif
|
#endif
|
||||||
triesLeft--;
|
triesLeft--;
|
||||||
status = gIsVC
|
status = (gEmulator & EMU_WIIVC)
|
||||||
? osEepromLongReadVC(&gSIEventMesgQueue, offset, buffer, size)
|
? osEepromLongReadVC(&gSIEventMesgQueue, offset, buffer, size)
|
||||||
: osEepromLongRead (&gSIEventMesgQueue, offset, buffer, size);
|
: osEepromLongRead (&gSIEventMesgQueue, offset, buffer, size);
|
||||||
#if ENABLE_RUMBLE
|
#if ENABLE_RUMBLE
|
||||||
@@ -106,7 +106,7 @@ static s32 write_eeprom_data(void *buffer, s32 size) {
|
|||||||
block_until_rumble_pak_free();
|
block_until_rumble_pak_free();
|
||||||
#endif
|
#endif
|
||||||
triesLeft--;
|
triesLeft--;
|
||||||
status = gIsVC
|
status = (gEmulator & EMU_WIIVC)
|
||||||
? osEepromLongWriteVC(&gSIEventMesgQueue, offset, buffer, size)
|
? osEepromLongWriteVC(&gSIEventMesgQueue, offset, buffer, size)
|
||||||
: osEepromLongWrite (&gSIEventMesgQueue, offset, buffer, size);
|
: osEepromLongWrite (&gSIEventMesgQueue, offset, buffer, size);
|
||||||
#if ENABLE_RUMBLE
|
#if ENABLE_RUMBLE
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
#include "vc_check.h"
|
|
||||||
|
|
||||||
u8 gIsVC = FALSE;
|
|
||||||
|
|
||||||
// literally return what was passed
|
|
||||||
f32 round_double_to_float(f64 v)
|
|
||||||
{
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef VC_CHECK_H
|
|
||||||
#define VC_CHECK_H
|
|
||||||
|
|
||||||
#include "sm64.h"
|
|
||||||
|
|
||||||
extern u8 gIsVC;
|
|
||||||
|
|
||||||
// This function must not be inlined by the compiler so I move it to a different C file
|
|
||||||
f32 round_double_to_float(f64);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This check forces RTZ bug on vc
|
|
||||||
* If console is N64/adequate Emu round-to-nearest (RTN) rounding mode is used
|
|
||||||
* If console is VC round-to-zero (RTZ) mode is used
|
|
||||||
*
|
|
||||||
* The double value 0.9999999999999999 used is 0x3FEFFFFFFFFFFFFF in binary
|
|
||||||
* Exponent=01111111110, Mantissa=1111111111111111111111111111111111111111111111111111
|
|
||||||
* RTZ will output not 1.0f, RTN will output exactly 1.0f
|
|
||||||
*/
|
|
||||||
#define IS_VC() (1.0f != round_double_to_float(0.9999999999999999))
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <ultra64.h>
|
#include <ultra64.h>
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
#include <PR/gs2dex.h>
|
#include <PR/gs2dex.h>
|
||||||
|
#include "game/emutest.h"
|
||||||
|
|
||||||
#ifndef S2D_CONFIG_H
|
#ifndef S2D_CONFIG_H
|
||||||
#define S2D_CONFIG_H
|
#define S2D_CONFIG_H
|
||||||
@@ -88,11 +89,11 @@ extern char *proutSprintf(char *dst, const char *src, size_t count);
|
|||||||
#define TEX_BITDEPTH 8
|
#define TEX_BITDEPTH 8
|
||||||
|
|
||||||
#define seg2virt segmented_to_virtual
|
#define seg2virt segmented_to_virtual
|
||||||
#define gIsEmulator (!gIsConsole)
|
#define gIsEmulator (!(gEmulator & EMU_CONSOLE))
|
||||||
|
|
||||||
// Texture resolution (pixels on the texture per pixel on the framebuffer)
|
// Texture resolution (pixels on the texture per pixel on the framebuffer)
|
||||||
#define TEX_RES 1
|
#define TEX_RES 1
|
||||||
|
|
||||||
#define _NUM_CACHE (4096 / (TEX_WIDTH * TEX_HEIGHT * (TEX_BITDEPTH / 8)))
|
#define _NUM_CACHE (4096 / (TEX_WIDTH * TEX_HEIGHT * (TEX_BITDEPTH / 8)))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user