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:
Matt Pharoah
2023-08-28 18:03:26 -04:00
committed by GitHub
parent 0138b8ea53
commit febcb71ea3
20 changed files with 278 additions and 92 deletions

View File

@@ -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
- **Pyro Jay**: Texture improvements, repo banner art, some QoL stuff
- **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
- **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
@@ -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)
- 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
- 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) *
- 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. *
@@ -105,7 +106,7 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
**Neat Misc. Changes:**
- 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. *
- 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. *
@@ -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
- 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
- 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.
- Getting HVQM FMV support to work with the game is WIP.

View 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

View File

@@ -336,7 +336,6 @@ index ad9fdb7d..26e1f000 100644
@@ -29,6 +29,9 @@
#include "puppycam2.h"
#include "debug_box.h"
#include "vc_check.h"
+#ifdef REONUCAM
+#include "camera.h"
+#endif

View File

@@ -42,7 +42,7 @@
/**
* 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.
* 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

View File

@@ -160,6 +160,7 @@ SECTIONS
#ifdef EEP
KEEP(BUILD_DIR/asm/vc_bin.o(.text*));
#endif
KEEP(BUILD_DIR/asm/pj64_get_count_factor_asm.o(.text*));
KEEP(BUILD_DIR/asm/round.o(.text*));
BUILD_DIR/src/boot*.o(.text*);

View File

@@ -6,9 +6,8 @@
#include "synthesis.h"
#include "seqplayer.h"
#include "effects.h"
#include "game/game_init.h"
#include "game/emutest.h"
#include "game/puppyprint.h"
#include "game/vc_check.h"
#include "game/debug.h"
#include "string.h"
@@ -1171,7 +1170,7 @@ void audio_reset_session(s32 reverbPresetId) {
if (gAudioLoadLock != AUDIO_LOCK_UNINITIALIZED) {
gAudioLoadLock = AUDIO_LOCK_LOADING;
if (!gIsVC) {
if (!(gEmulator & EMU_WIIVC)) {
gAudioFrameCount = 0;
while (gAudioFrameCount < 1) {
// spin
@@ -1325,7 +1324,7 @@ void audio_reset_session(void) {
gAudioBufferParameters.minAiBufferLength *= gAudioBufferParameters.presetUnk4;
gAudioBufferParameters.updatesPerFrame *= gAudioBufferParameters.presetUnk4;
if (gIsConsole)
if (gEmulator & EMU_CONSOLE)
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_CONSOLE;
else
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_EMULATOR;
@@ -1352,7 +1351,7 @@ void audio_reset_session(void) {
gMinAiBufferLength = gSamplesPerFrameTarget - 0x10;
gAudioUpdatesPerFrame = updatesPerFrame = gSamplesPerFrameTarget / 160 + 1;
if (gIsConsole)
if (gEmulator & EMU_CONSOLE)
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_CONSOLE;
else
gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_EMULATOR;

View File

@@ -15,7 +15,6 @@
#include "game/main.h"
#include "game/rumble_init.h"
#include "game/version.h"
#include "game/vc_check.h"
#ifdef UNF
#include "usb/usb.h"
#include "usb/debug.h"
@@ -23,8 +22,7 @@
#include "game/puppyprint.h"
#include "game/puppylights.h"
#include "game/profiling.h"
#include "game/vc_check.h"
#include "game/emutest.h"
// Message IDs
enum MessageIDs {
@@ -318,21 +316,6 @@ void alert_rcp_hung_up(void) {
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.
* 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();
alloc_pool();
load_engine_code_segment();
gIsVC = IS_VC();
detect_emulator();
#ifndef UNF
crash_screen_init();
#endif
@@ -384,14 +367,8 @@ void thread3_main(UNUSED void *arg) {
osSyncPrintf("Linker : %s\n", __linker__);
#endif
if (IO_READ(DPC_CLOCK_REG) == 0) {
gIsConsole = FALSE;
if (!(gEmulator & EMU_CONSOLE)) {
gBorderHeight = BORDER_HEIGHT_EMULATOR;
if (!gIsVC) {
check_cache_emulation();
} else {
gCacheEmulated = FALSE;
}
#ifdef RCVI_HACK
VI.comRegs.vSync = 525*20;
change_vi(&VI, SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -400,7 +377,6 @@ void thread3_main(UNUSED void *arg) {
osViSetSpecialFeatures(OS_VI_GAMMA_OFF);
#endif
} else {
gIsConsole = TRUE;
gBorderHeight = BORDER_HEIGHT_CONSOLE;
}
#ifdef DEBUG

View File

@@ -29,6 +29,7 @@
#include "game/puppycam2.h"
#include "game/puppyprint.h"
#include "game/puppylights.h"
#include "game/emutest.h"
#include "config.h"
@@ -740,7 +741,7 @@ static void level_cmd_set_music(void) {
if (sCurrAreaIndex != -1) {
gAreas[sCurrAreaIndex].musicParam = CMD_GET(s16, 2);
#ifdef BETTER_REVERB
if (gIsConsole)
if (gEmulator & EMU_CONSOLE)
gAreas[sCurrAreaIndex].betterReverbPreset = CMD_GET(u8, 4);
else
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) {
#ifdef BETTER_REVERB
// Must come before set_background_music()
if (gIsConsole)
if (gEmulator & EMU_CONSOLE)
gBetterReverbPresetValue = CMD_GET(u8, 4);
else
gBetterReverbPresetValue = CMD_GET(u8, 5);
@@ -907,7 +908,7 @@ static void level_cmd_puppylight_node(void) {
static void level_cmd_set_echo(void) {
if (sCurrAreaIndex >= 0 && sCurrAreaIndex < AREA_COUNT) {
gAreaData[sCurrAreaIndex].useEchoOverride = TRUE;
if (gIsConsole)
if (gEmulator & EMU_CONSOLE)
gAreaData[sCurrAreaIndex].echoOverride = CMD_GET(s8, 2);
else
gAreaData[sCurrAreaIndex].echoOverride = CMD_GET(s8, 3);

167
src/game/emutest.c Normal file
View 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
View 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
View 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
View 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

View File

@@ -28,9 +28,12 @@
#include "puppyprint.h"
#include "puppycam2.h"
#include "debug_box.h"
#include "vc_check.h"
#include "vc_ultra.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
struct Controller gControllers[3];
@@ -46,8 +49,6 @@ OSContStatus gControllerStatuses[4];
OSContPadEx gControllerPads[4];
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.
u8 gIsConsole = TRUE; // Needs to be initialized before audio_reset_session is called
u8 gCacheEmulated = TRUE;
u8 gBorderHeight;
#ifdef VANILLA_STYLE_CUSTOM_DEBUG
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
// 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.
if (gIsConsole || gIsVC || gCacheEmulated) {
// Currently, Ares and Simple64 have issues with single buffering so disable it there as well.
if (gEmulator & INSTANT_INPUT_BLACKLIST) {
sRenderingFramebuffer++;
}
gGlobalTimer++;
@@ -444,7 +445,7 @@ void display_and_vsync(void) {
osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
#endif
// 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) {
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 (controller->controllerData != NULL) {
// 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 newButton = oldButton & ~(Z_TRIG | L_TRIG);
if (oldButton & Z_TRIG) {
@@ -668,7 +669,7 @@ void init_controllers(void) {
#ifdef EEP
// strangely enough, the EEPROM probe for save data is done in this function.
// save pak detection?
gEepromProbe = gIsVC
gEepromProbe = (gEmulator & EMU_WIIVC)
? osEepromProbeVC(&gSIEventMesgQueue)
: osEepromProbe (&gSIEventMesgQueue);
#endif
@@ -695,7 +696,7 @@ void init_controllers(void) {
gControllers[cont++].controllerData = &gControllerPads[port];
}
}
if ((__osControllerTypes[1] == CONT_TYPE_GCN) && (gIsConsole)) {
if ((__osControllerTypes[1] == CONT_TYPE_GCN) && (gEmulator & EMU_CONSOLE)) {
gGamecubeControllerPort = 1;
gPlayer1Controller = &gControllers[1];
} else {

View File

@@ -48,8 +48,6 @@ extern u8 *gGfxPoolEnd;
extern struct GfxPool *gGfxPool;
extern u8 gControllerBits;
extern s8 gGamecubeControllerPort;
extern u8 gIsConsole;
extern u8 gCacheEmulated;
extern u8 gBorderHeight;
#ifdef VANILLA_STYLE_CUSTOM_DEBUG
extern u8 gCustomDebugMode;

View File

@@ -32,6 +32,7 @@
#include "save_file.h"
#include "sound_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->marioBodyState = &gBodyStates[0];
gMarioState->animList = &gMarioAnimsBuf;
if (gIsConsole && __osControllerTypes[1] == CONT_TYPE_GCN) {
if ((gEmulator & EMU_CONSOLE) && __osControllerTypes[1] == CONT_TYPE_GCN) {
gMarioState->controller = &gControllers[1];
} else {
gMarioState->controller = &gControllers[0];

View File

@@ -17,6 +17,7 @@
#include "behavior_data.h"
#include "string.h"
#include "color_presets.h"
#include "emutest.h"
#include "config.h"
#include "config/config_world.h"
@@ -314,7 +315,7 @@ void switch_ucode(s32 ucode) {
break;
case GRAPH_NODE_UCODE_REJ:
// Use .rej Microcode, skip sub-pixel processing on console
if (gIsConsole) {
if (gEmulator & EMU_CONSOLE) {
gSPLoadUcodeL(gDisplayListHead++, gspF3DLX2_Rej_fifo); // F3DLX2_Rej
} else {
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
// horizontal value to account for viewport widescreen hacks.
if(!gIsConsole){
if(!(gEmulator & EMU_CONSOLE)){
node->halfFovHorizontal = 9999.0f;
}
#endif
@@ -614,7 +615,7 @@ static f32 get_dist_from_camera(Vec3f pos) {
*/
void geo_process_level_of_detail(struct GraphNodeLevelOfDetail *node) {
#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
f32 distanceFromCam = get_dist_from_camera(gMatStack[gMatStackIndex][3]);
#endif

View File

@@ -13,6 +13,7 @@
#include "level_commands.h"
#include "rumble_init.h"
#include "config.h"
#include "emutest.h"
#ifdef SRAM
#include "sram.h"
#endif
@@ -55,7 +56,6 @@ s8 gLevelToCourseNumTable[] = {
STATIC_ASSERT(ARRAY_COUNT(gLevelToCourseNumTable) == LEVEL_COUNT - 1,
"change this array if you are adding levels");
#ifdef EEP
#include "vc_check.h"
#include "vc_ultra.h"
/**
@@ -76,7 +76,7 @@ static s32 read_eeprom_data(void *buffer, s32 size) {
block_until_rumble_pak_free();
#endif
triesLeft--;
status = gIsVC
status = (gEmulator & EMU_WIIVC)
? osEepromLongReadVC(&gSIEventMesgQueue, offset, buffer, size)
: osEepromLongRead (&gSIEventMesgQueue, offset, buffer, size);
#if ENABLE_RUMBLE
@@ -106,7 +106,7 @@ static s32 write_eeprom_data(void *buffer, s32 size) {
block_until_rumble_pak_free();
#endif
triesLeft--;
status = gIsVC
status = (gEmulator & EMU_WIIVC)
? osEepromLongWriteVC(&gSIEventMesgQueue, offset, buffer, size)
: osEepromLongWrite (&gSIEventMesgQueue, offset, buffer, size);
#if ENABLE_RUMBLE

View File

@@ -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;
}

View File

@@ -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

View File

@@ -1,6 +1,7 @@
#include <ultra64.h>
#include "macros.h"
#include <PR/gs2dex.h>
#include "game/emutest.h"
#ifndef 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 seg2virt segmented_to_virtual
#define gIsEmulator (!gIsConsole)
#define gIsEmulator (!(gEmulator & EMU_CONSOLE))
// Texture resolution (pixels on the texture per pixel on the framebuffer)
#define TEX_RES 1
#define _NUM_CACHE (4096 / (TEX_WIDTH * TEX_HEIGHT * (TEX_BITDEPTH / 8)))
#endif
#endif