From 1a71619f47513e73e1a0829bf2733d510ac01bf1 Mon Sep 17 00:00:00 2001 From: arthurtilly <32559225+arthurtilly@users.noreply.github.com> Date: Wed, 26 Oct 2022 19:12:29 +1300 Subject: [PATCH 01/13] Imminent fixes for bugs found on master branch (#512) * The vanilla level checks define for Yoshi is inverted, causing him to require 120 stars when it is off and appear at 0 stars when it's on * The downwarp fix results in Mario levitating in midair when grabbing Bowser midair. While downwarps should still be fixed, the change should be reverted immediately until a better fix is made. * Some checks of Mario's floor class were using the wrong defines, which can lead to unexpected behavior in the event anyone wants to reorder surface types. By default the SURFACE_CLASS_SLIPPERY and SURFACE_SLIPPERY defines have the same value, which is why this mistake is hard to notice. * The firsty frames define was implemented poorly, not allowing for vanilla firsty behavior no matter what the values were set to. This has been reverted, while avoiding the UB in the original vanilla code. * Removed the ledge grab changes that fix QSLGs and change the false ledgegrab define since Arceveti wanted to in his PR --- README.md | 3 +-- include/config/config_movement.h | 7 ++----- include/surface_terrains.h | 2 +- src/engine/surface_collision.c | 2 +- src/game/behaviors/yoshi.inc.c | 2 +- src/game/mario.c | 24 ++++++++++++------------ src/game/mario_actions_airborne.c | 7 ++----- src/game/mario_actions_automatic.c | 2 -- src/game/mario_step.c | 11 ++++++----- 9 files changed, 26 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index c399e901..0cb169fa 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - **ArcticJaguar725**: Most audio configuration and layout changes, colored ia4 text, floombas, various bugfixes, and more - **CowQuack**: Adjustable skybox sizes, area-specific skybox function - **thecozies**: Water surface types, general maintenance, and time -- **MrComit**: General use object defines, JUMP_KICK_FIX, LEDGE_GRABS_CHECK_SLOPE_ANGLE +- **MrComit**: General use object defines, JUMP_KICK_FIX - **aglab2**: Bugfixes (particularly puppycam), refactor stuff - **someone2639**: math.s and crash screen disam, stack trace, map packing, shiftable segments 2, S2DEX engine - **Arthurtilly**: Platform Displacement 2 @@ -61,7 +61,6 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff - Toggle to disable fall damage and the fall damage sound * - Nonstop stars * - Removed course-specific camera processing * -- You can increase the number of frames that you have to perform a firsty * - Ability to set Mario's movement speed when hanging from a ceiling * - Tighter hanging controls (Mario will face the direction of the analog stick directly while hanging from a ceiling) * - reonucam3: custom camera by Reonu. This is included as a .patch file in the enhancements folder, you need to apply it if you want this camera. diff --git a/include/config/config_movement.h b/include/config/config_movement.h index 6fa9ff7f..95d56713 100644 --- a/include/config/config_movement.h +++ b/include/config/config_movement.h @@ -68,14 +68,11 @@ // Allows Mario to grab hangable ceilings from any state. #define HANGING_FIX -// The last frame after hitting a wall that will be considered a firsty when wallkicking. -#define FIRSTY_LAST_FRAME 1 - // The maximum angle the player can wall kick, in degrees. 0..90. To allow 45 degree wall kicks, you must supply `46` to allow 45 and under. #define WALL_KICK_DEGREES 45 -// This is vanilla behavior, disable it to allow ledge grabbing regardless of floor pitch. -// #define LEDGE_GRABS_CHECK_SLOPE_ANGLE +// Makes Mario unable to ledge grab steep slopes to prevent false ledge grabs. +#define DONT_LEDGE_GRAB_STEEP_SLOPES // Disables BLJs and crushes SimpleFlips's dreams. // #define DISABLE_BLJ diff --git a/include/surface_terrains.h b/include/surface_terrains.h index 95b20aa3..e39be5cf 100644 --- a/include/surface_terrains.h +++ b/include/surface_terrains.h @@ -244,7 +244,7 @@ enum SurfaceTypes { enum SurfaceClass { SURFACE_CLASS_DEFAULT, - SURFACE_CLASS_VERY_SLIPPERY = 0x0013, + SURFACE_CLASS_VERY_SLIPPERY, SURFACE_CLASS_SLIPPERY, SURFACE_CLASS_NOT_SLIPPERY }; diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 73bb7034..2e5f67d7 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -704,7 +704,7 @@ s32 find_water_level(s32 x, s32 z) { // TODO: Allow y pos // If the location is within a water box and it is a water box. // Water is less than 50 val only, while above is gas and such. - if (loX < x && x < hiX && loZ < z && z < hiZ && val < 50) { + if (loX <= x && x <= hiX && loZ <= z && z <= hiZ && val < 50) { // Set the water height. Since this breaks, only return the first height. waterLevel = *p; break; diff --git a/src/game/behaviors/yoshi.inc.c b/src/game/behaviors/yoshi.inc.c index a6eb0a44..26a76fad 100644 --- a/src/game/behaviors/yoshi.inc.c +++ b/src/game/behaviors/yoshi.inc.c @@ -11,7 +11,7 @@ void bhv_yoshi_init(void) { o->oBuoyancy = 1.3f; o->oInteractionSubtype = INT_SUBTYPE_NPC; -#if defined(ENABLE_VANILLA_LEVEL_SPECIFIC_CHECKS) || defined(UNLOCK_ALL) +#if !defined(ENABLE_VANILLA_LEVEL_SPECIFIC_CHECKS) || defined(UNLOCK_ALL) if (sYoshiDead == TRUE) { #else if ((save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_NUM_TO_INDEX(COURSE_MIN), COURSE_NUM_TO_INDEX(COURSE_MAX)) < 120) diff --git a/src/game/mario.c b/src/game/mario.c index 90f4da1d..acce2d69 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -536,10 +536,10 @@ u32 mario_floor_is_slippery(struct MarioState *m) { } switch (mario_get_floor_class(m)) { - case SURFACE_VERY_SLIPPERY: normY = COS10; break; - case SURFACE_SLIPPERY: normY = COS20; break; - default: normY = COS38; break; - case SURFACE_NOT_SLIPPERY: normY = 0.0f; break; + case SURFACE_CLASS_VERY_SLIPPERY: normY = COS10; break; + case SURFACE_CLASS_SLIPPERY: normY = COS20; break; + default: normY = COS38; break; + case SURFACE_CLASS_NOT_SLIPPERY: normY = 0.0f; break; } return m->floor->normal.y <= normY; @@ -557,10 +557,10 @@ s32 mario_floor_is_slope(struct MarioState *m) { } switch (mario_get_floor_class(m)) { - case SURFACE_VERY_SLIPPERY: normY = COS5; break; - case SURFACE_SLIPPERY: normY = COS10; break; - default: normY = COS15; break; - case SURFACE_NOT_SLIPPERY: normY = COS20; break; + case SURFACE_CLASS_VERY_SLIPPERY: normY = COS5; break; + case SURFACE_CLASS_SLIPPERY: normY = COS10; break; + default: normY = COS15; break; + case SURFACE_CLASS_NOT_SLIPPERY: normY = COS20; break; } return m->floor->normal.y <= normY; @@ -584,10 +584,10 @@ s32 mario_floor_is_steep(struct MarioState *m) { // This does not matter in vanilla game practice. if (!mario_facing_downhill(m, FALSE)) { switch (mario_get_floor_class(m)) { - case SURFACE_VERY_SLIPPERY: normY = COS15; break; - case SURFACE_SLIPPERY: normY = COS20; break; - default: normY = COS30; break; - case SURFACE_NOT_SLIPPERY: normY = COS30; break; + case SURFACE_CLASS_VERY_SLIPPERY: normY = COS15; break; + case SURFACE_CLASS_SLIPPERY: normY = COS20; break; + default: normY = COS30; break; + case SURFACE_CLASS_NOT_SLIPPERY: normY = COS30; break; } return m->floor->normal.y <= normY; diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 7103228f..26051395 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -1273,7 +1273,7 @@ s32 act_air_hit_wall(struct MarioState *m) { mario_drop_held_object(m); } - if (++(m->actionTimer) <= FIRSTY_LAST_FRAME) { + if (++(m->actionTimer) <= 2) { if (m->input & INPUT_A_PRESSED) { m->vel[1] = 52.0f; m->faceAngle[1] += 0x8000; @@ -1299,12 +1299,9 @@ s32 act_air_hit_wall(struct MarioState *m) { return set_mario_action(m, ACT_SOFT_BONK, 0); } -#if FIRSTY_LAST_FRAME > 1 set_mario_animation(m, MARIO_ANIM_START_WALLKICK); - m->marioObj->header.gfx.angle[1] = m->wallYaw; -#endif - return FALSE; + return TRUE; } s32 act_forward_rollout(struct MarioState *m) { diff --git a/src/game/mario_actions_automatic.c b/src/game/mario_actions_automatic.c index 117e1cb4..6fd5ea36 100644 --- a/src/game/mario_actions_automatic.c +++ b/src/game/mario_actions_automatic.c @@ -565,11 +565,9 @@ s32 act_ledge_grab(struct MarioState *m) { if (m->actionTimer < 10) { m->actionTimer++; } -#ifdef LEDGE_GRABS_CHECK_SLOPE_ANGLE if (m->floor->normal.y < COS25) { return let_go_of_ledge(m); } -#endif if (m->input & (INPUT_Z_PRESSED | INPUT_OFF_FLOOR)) { return let_go_of_ledge(m); } diff --git a/src/game/mario_step.c b/src/game/mario_step.c index 2b1ceb08..eb9923fd 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -259,10 +259,9 @@ s32 stationary_ground_step(struct MarioState *m) { if (takeStep) { stepResult = perform_ground_step(m); } else { - // Hackersm64: this condition fixes potential downwarps - if (m->pos[1] <= m->floorHeight + 160.0f) { - m->pos[1] = m->floorHeight; - } + //! TODO - This is responsible for many stationary downwarps but is + // important for stuff like catching Bowser in midair, figure out a good way to fix + m->pos[1] = m->floorHeight; vec3f_copy(marioObj->header.gfx.pos, m->pos); vec3s_set(marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); @@ -404,8 +403,10 @@ struct Surface *check_ledge_grab(struct MarioState *m, struct Surface *prevWall, if (ledgeFloor == NULL || (*ledgeFloor) == NULL || ledgePos[1] < nextPos[1] + 100.0f +#ifdef DONT_LEDGE_GRAB_STEEP_SLOPES || (*ledgeFloor)->normal.y < COS25 // H64 TODO: check if floor is actually slippery - || SURFACE_IS_UNSAFE((*ledgeFloor)->type)) { +#endif + ) { return NULL; } From b8e22f2fbdbe0e0ae1b65f9042ad66560bcfdbfb Mon Sep 17 00:00:00 2001 From: axollyon <20480418+axollyon@users.noreply.github.com> Date: Thu, 27 Oct 2022 01:17:08 -0400 Subject: [PATCH 02/13] Update version to 2.0.4 (#515) --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index f256be60..8a5b818b 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -v2.0.3 +v2.0.4 From b1146308a7babdff7b611ad4c64d141dcc59a6c0 Mon Sep 17 00:00:00 2001 From: Gregory Heskett Date: Wed, 23 Nov 2022 15:57:44 -0500 Subject: [PATCH 03/13] HackerSM64 2.0.5 (#517) * Bugfix: race condition with accessing cleared audio memory pools * Bugfix: skyboxes access tiles out of range when looking straight down (#518) * Vscode fixes (#516) * Revert s32 angles and remove Angle typedef usage (#529) * Fix some surface shadowing (#531) * Delete rtc.h * Remove `wait_for_audio_frames()` Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com> Co-authored-by: Arceveti <73617174+Arceveti@users.noreply.github.com> Co-authored-by: JoshDuMan <40190173+JoshDuMan@users.noreply.github.com> --- .vscode/c_cpp_properties.json | 2 +- Makefile | 8 ++ include/rtc.h | 71 ----------------- include/types.h | 14 +--- src/audio/heap.c | 53 ++++++------- src/engine/math_util.c | 50 ++++++------ src/engine/math_util.h | 76 +++++++++---------- src/engine/surface_collision.c | 2 +- src/game/behaviors/boo.inc.c | 2 +- src/game/behaviors/hoot.inc.c | 4 +- .../lll_octagonal_rotating_mesh.inc.c | 8 +- src/game/behaviors/platform_on_track.inc.c | 2 +- src/game/behaviors/spawn_star.inc.c | 2 +- src/game/camera.c | 4 +- src/game/camera.h | 4 +- src/game/macro_special_objects.c | 2 +- src/game/skybox.c | 4 + 17 files changed, 119 insertions(+), 189 deletions(-) delete mode 100755 include/rtc.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 71be5a3d..c70dc8aa 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -33,7 +33,7 @@ "compilerPath": "/usr/bin/mips-linux-gnu-gcc", "cStandard": "gnu17", "cppStandard": "gnu++14", - "intelliSenseMode": "linux-gcc-x64" + "intelliSenseMode": "linux-gcc-x86" } ], "version": 4 diff --git a/Makefile b/Makefile index 65345527..977d2a2c 100644 --- a/Makefile +++ b/Makefile @@ -870,8 +870,16 @@ $(ELF): $(BUILD_DIR)/sm64_prelim.elf $(BUILD_DIR)/asm/debug/map.o $(O_FILES) $(Y $(V)$(LD) --gc-sections -L $(BUILD_DIR) -T undefined_syms.txt -T $(BUILD_DIR)/$(LD_SCRIPT) -T goddard.txt -Map $(BUILD_DIR)/sm64.$(VERSION).map --no-check-sections $(addprefix -R ,$(SEG_FILES)) -o $@ $(O_FILES) -L$(LIBS_DIR) -l$(ULTRALIB) -Llib $(LINK_LIBRARIES) -u sprintf -u osMapTLB -Llib/gcclib/$(LIBGCCDIR) -lgcc -lrtc # Build ROM +ifeq (n,$(findstring n,$(firstword -$(MAKEFLAGS)))) +# run with -n / --dry-run +$(ROM): + @$(PRINT) "$(BLUE)DRY RUNS ARE DISABLED$(NO_COL)\n" +else +# not running with -n / --dry-run $(ROM): $(ELF) $(call print,Building ROM:,$<,$@) +endif + ifeq ($(CONSOLE),n64) $(V)$(OBJCOPY) --pad-to=0x101000 --gap-fill=0xFF $< $@ -O binary else ifeq ($(CONSOLE),bb) diff --git a/include/rtc.h b/include/rtc.h deleted file mode 100755 index f6aec6a7..00000000 --- a/include/rtc.h +++ /dev/null @@ -1,71 +0,0 @@ -/*--------------------------------------------------------------------- - Copyright (C) 1997, 1998 Nintendo. - - File rtc.h - Coded by Shigeo Kimura. Oct 14, 1997. - Modified by Koji Mitsunari. Jan 22, 2001. - Comments Real Time Clock Library - ---------------------------------------------------------------------*/ -#ifndef _rtc_h_ -#define _rtc_h_ - -/*----------------------------------------------------------------------- - * Macro & constant definitions - *-----------------------------------------------------------------------*/ -/* Controller type */ -#define CONT_TYPE_RTC 0x1000 /* from os.h */ -#define RTC_WAIT 300 - -/* RTC status signed 32bits */ -#define RTC_NG_NOTHING 0x8000 -#define RTC_NG_WRITE 0x0100 -#define RTC_NG_ADDR 0x0200 -#define RTC_STATUS_BUSY 0x0080 -#define RTC_STATUS_DDOWN 0x0002 -#define RTC_STATUS_BDOWN 0x0001 - -/* RTC Error Code */ -#define CONT_ERR_RTC_BUSY 16 -#define CONT_ERR_RTC_BDOWN 17 -#define CONT_ERR_RTC_DDOWN 18 -#define CONT_ERR_RTC_BDDOWN 19 - -/* RTC bit status */ -#define RTC_EALM 0x80 -#define RTC_ALM 0x20 -#define RTC_WPB1 0x02 -#define RTC_WPB0 0x01 -#define RTC_MOD 0x04 -#define RTC_CHLD 0x02 -#define RTC_ADJ 0x01 - -#define RTC_ADDR_FLAG 0 -#define RTC_ADDR_RAM 1 -#define RTC_ADDR_TIME 2 - -typedef struct{ - u8 sec; /* second 0-59 */ - u8 min; /* minute 0-59 */ - u8 hour; /* hour 0-23 */ - u8 day; /* day 1-31 */ - u8 week; /* week 0-6(sun,mon,..,sat) */ - u8 month; /* month 1-12 */ - u16 year; /* year 1901-2099 */ -} OSRTCTime; - -/*----------------------------------------------------------------------- - * externs - *-----------------------------------------------------------------------*/ - -extern s32 osRTCInit( OSMesgQueue *mq); -extern s32 osRTCReadData( OSMesgQueue *mq, u8 *); -extern s32 osRTCWriteData( OSMesgQueue *mq, u8 *); -extern s32 osRTCGetTime( OSMesgQueue *mq, OSRTCTime *); -extern s32 osRTCSetTime( OSMesgQueue *mq, OSRTCTime *); -extern u32 osRTCGetIntervalTime(OSRTCTime *, OSRTCTime *); -extern s32 osRTCGetLaterTime(OSMesgQueue *mq, u32, OSRTCTime *); -extern s32 osRTCSetAlarm( OSMesgQueue *mq, u8, u8); -extern s32 osRTCGetAlarmStat(OSMesgQueue *mq, u8 *, u8 *, int *); -extern s32 osRTCProbe( OSMesgQueue *mq); - -#endif /* _rtc_h_ */ diff --git a/include/types.h b/include/types.h index 64955f84..5a596316 100644 --- a/include/types.h +++ b/include/types.h @@ -98,12 +98,6 @@ typedef s8 ObjAction8; typedef s32 ObjAction32; typedef s16 ColFlags; -// -- Angle -- -typedef s16 Angle; -typedef u16 UAngle; -typedef s32 Angle32; -typedef Angle Vec3a[3]; - // -- Collision -- typedef ROOM_DATA_TYPE RoomData; typedef COLLISION_DATA_TYPE Collision; // Collision is by default an s16, but it's best to have it match the type of COLLISION_DATA_TYPE @@ -489,10 +483,10 @@ struct MarioState { Vec3f prevPos; f32 lateralSpeed; f32 moveSpeed; - Angle movePitch; - Angle moveYaw; - Angle ceilYaw; - Angle wallYaw; + s16 movePitch; + s16 moveYaw; + s16 ceilYaw; + s16 wallYaw; // -- HackerSM64 MarioState fields end -- }; diff --git a/src/audio/heap.c b/src/audio/heap.c index 60a9218a..0c75c136 100644 --- a/src/audio/heap.c +++ b/src/audio/heap.c @@ -969,22 +969,6 @@ s32 audio_shut_down_and_reset_step(void) { } return (gAudioResetStatus < 3); } -#else -/** - * Waits until a specified number of audio frames have been created - */ -void wait_for_audio_frames(s32 frames) { - // VC emulator stubs this function because busy loops are not supported - // Technically we can put infinite loop that _looks_ like -O0 for emu but this is cleaner - //if (gIsVC) { - return; - //} - gAudioFrameCount = 0; - // Sound thread will update gAudioFrameCount - while (gAudioFrameCount < frames) { - // spin - } -} #endif u8 sAudioFirstBoot = 0; @@ -1169,22 +1153,33 @@ void init_reverb_us(s32 presetId) { #if defined(VERSION_JP) || defined(VERSION_US) void audio_reset_session(struct AudioSessionSettings *preset, s32 presetId) { if (sAudioFirstBoot) { - bzero(&gAiBuffers[0][0], (AIBUFFER_LEN * NUMAIBUFFERS)); - persistent_pool_clear(&gSeqLoadedPool.persistent); - persistent_pool_clear(&gBankLoadedPool.persistent); - temporary_pool_clear( &gSeqLoadedPool.temporary); - temporary_pool_clear( &gBankLoadedPool.temporary); - reset_bank_and_seq_load_status(); + if (gAudioLoadLock != AUDIO_LOCK_UNINITIALIZED) { + gAudioLoadLock = AUDIO_LOCK_LOADING; - init_reverb_us(presetId); - bzero(&gAiBuffers[0][0], (AIBUFFER_LEN * NUMAIBUFFERS)); - gAudioFrameCount = 0; - if (!gIsVC) { - while (gAudioFrameCount < 1) { - // spin + if (!gIsVC) { + gAudioFrameCount = 0; + while (gAudioFrameCount < 1) { + // spin + } + } + + for (s32 i = 0; i < gMaxSimultaneousNotes; i++) { + gNotes[i].enabled = FALSE; + } + + persistent_pool_clear(&gSeqLoadedPool.persistent); + persistent_pool_clear(&gBankLoadedPool.persistent); + temporary_pool_clear( &gSeqLoadedPool.temporary); + temporary_pool_clear( &gBankLoadedPool.temporary); + reset_bank_and_seq_load_status(); + + init_reverb_us(presetId); + bzero(&gAiBuffers[0][0], (AIBUFFER_LEN * NUMAIBUFFERS)); + + if (gAudioLoadLock != AUDIO_LOCK_UNINITIALIZED) { + gAudioLoadLock = AUDIO_LOCK_NOT_LOADING; } } - bzero(&gAiBuffers[0][0], (AIBUFFER_LEN * NUMAIBUFFERS)); return; } #else diff --git a/src/engine/math_util.c b/src/engine/math_util.c index c410e558..db043e95 100644 --- a/src/engine/math_util.c +++ b/src/engine/math_util.c @@ -503,7 +503,7 @@ void mtxf_rotate_xyz_and_translate_and_mul(Vec3s rot, Vec3f trans, Mat4 dest, Ma * at the position 'to'. The up-vector is assumed to be (0, 1, 0), but the 'roll' * angle allows a bank rotation of the camera. */ -void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s32 roll) { +void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s16 roll) { Vec3f colX, colY, colZ; register f32 dx = (to[0] - from[0]); register f32 dz = (to[2] - from[2]); @@ -543,7 +543,7 @@ void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s32 roll) { * 'scale' is the scale of the object. * 'angle' rotates the object while still facing the camera. */ -void mtxf_billboard(Mat4 dest, Mat4 mtx, Vec3f position, Vec3f scale, s32 angle) { +void mtxf_billboard(Mat4 dest, Mat4 mtx, Vec3f position, Vec3f scale, s16 angle) { register s32 i; register f32 sx = scale[0]; register f32 sy = scale[1]; @@ -592,7 +592,7 @@ void mtxf_billboard(Mat4 dest, Mat4 mtx, Vec3f position, Vec3f scale, s32 angle) * 'scale' is the scale of the shadow * 'yaw' is the angle which it should face */ -void mtxf_shadow(Mat4 dest, Mat4 src, Vec3f upDir, Vec3f pos, Vec3f scale, s32 yaw) { +void mtxf_shadow(Mat4 dest, Mat4 src, Vec3f upDir, Vec3f pos, Vec3f scale, s16 yaw) { Vec3f lateralDir; Vec3f leftDir; Vec3f forwardDir; @@ -621,7 +621,7 @@ void mtxf_shadow(Mat4 dest, Mat4 src, Vec3f upDir, Vec3f pos, Vec3f scale, s32 y * 'yaw' is the angle which it should face * 'pos' is the object's position in the world */ -void mtxf_align_terrain_normal(Mat4 dest, Vec3f upDir, Vec3f pos, s32 yaw) { +void mtxf_align_terrain_normal(Mat4 dest, Vec3f upDir, Vec3f pos, s16 yaw) { Vec3f lateralDir; Vec3f leftDir; Vec3f forwardDir; @@ -646,7 +646,7 @@ void mtxf_align_terrain_normal(Mat4 dest, Vec3f upDir, Vec3f pos, s32 yaw) { * 'pos' is the object's position in the world * 'radius' is the distance from each triangle vertex to the center */ -void mtxf_align_terrain_triangle(Mat4 mtx, Vec3f pos, s32 yaw, f32 radius) { +void mtxf_align_terrain_triangle(Mat4 mtx, Vec3f pos, s16 yaw, f32 radius) { struct Surface *floor; Vec3f point0, point1, point2; Vec3f forward; @@ -765,7 +765,7 @@ UNUSED void mtxf_mul_vec3s(Mat4 mtx, Vec3s b) { #define MATENTRY(a, b) \ ((s16 *) mtx)[a ] = (((s32) b) >> 16); \ ((s16 *) mtx)[a + 16] = (((s32) b) & 0xFFFF); -void mtxf_rotate_xy(Mtx *mtx, s32 angle) { +void mtxf_rotate_xy(Mtx *mtx, s16 angle) { register s32 i = (coss(angle) * 0x10000); register s32 j = (sins(angle) * 0x10000); register f32 *temp = (f32 *)mtx; @@ -880,7 +880,7 @@ void vec3f_get_angle(Vec3f from, Vec3f to, s16 *pitch, s16 *yaw) { } /// Finds the horizontal distance and pitch between two vectors. -void vec3f_get_lateral_dist_and_pitch(Vec3f from, Vec3f to, f32 *lateralDist, Angle *pitch) { +void vec3f_get_lateral_dist_and_pitch(Vec3f from, Vec3f to, f32 *lateralDist, s16 *pitch) { Vec3f d; vec3_diff(d, to, from); *lateralDist = sqrtf(sqr(d[0]) + sqr(d[2])); @@ -888,7 +888,7 @@ void vec3f_get_lateral_dist_and_pitch(Vec3f from, Vec3f to, f32 *lateralDist, An } /// Finds the horizontal distance and yaw between two vectors. -void vec3f_get_lateral_dist_and_yaw(Vec3f from, Vec3f to, f32 *lateralDist, Angle *yaw) { +void vec3f_get_lateral_dist_and_yaw(Vec3f from, Vec3f to, f32 *lateralDist, s16 *yaw) { register f32 dx = (to[0] - from[0]); register f32 dz = (to[2] - from[2]); *lateralDist = sqrtf(sqr(dx) + sqr(dz)); @@ -896,7 +896,7 @@ void vec3f_get_lateral_dist_and_yaw(Vec3f from, Vec3f to, f32 *lateralDist, Angl } /// Finds the horizontal distance and angles between two vectors. -void vec3f_get_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *lateralDist, Angle *pitch, Angle *yaw) { +void vec3f_get_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *lateralDist, s16 *pitch, s16 *yaw) { Vec3f d; vec3_diff(d, to, from); *lateralDist = sqrtf(sqr(d[0]) + sqr(d[2])); @@ -905,7 +905,7 @@ void vec3f_get_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *lateralDist, An } /// Finds the distance and angles between two vectors. -void vec3f_get_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, Angle *pitch, Angle *yaw) { +void vec3f_get_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, s16 *pitch, s16 *yaw) { Vec3f d; vec3_diff(d, to, from); register f32 xz = (sqr(d[0]) + sqr(d[2])); @@ -913,7 +913,7 @@ void vec3f_get_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, Angle *pitch, Ang *pitch = atan2s(sqrtf(xz), d[1]); *yaw = atan2s(d[2], d[0]); } -void vec3s_get_dist_and_angle(Vec3s from, Vec3s to, s16 *dist, Angle *pitch, Angle *yaw) { +void vec3s_get_dist_and_angle(Vec3s from, Vec3s to, s16 *dist, s16 *pitch, s16 *yaw) { Vec3s d; vec3_diff(d, to, from); register f32 xz = (sqr(d[0]) + sqr(d[2])); @@ -921,7 +921,7 @@ void vec3s_get_dist_and_angle(Vec3s from, Vec3s to, s16 *dist, Angle *pitch, Ang *pitch = atan2s(sqrtf(xz), d[1]); *yaw = atan2s(d[2], d[0]); } -void vec3f_to_vec3s_get_dist_and_angle(Vec3f from, Vec3s to, f32 *dist, Angle *pitch, Angle *yaw) { +void vec3f_to_vec3s_get_dist_and_angle(Vec3f from, Vec3s to, f32 *dist, s16 *pitch, s16 *yaw) { Vec3f d; vec3_diff(d, to, from); register f32 xz = (sqr(d[0]) + sqr(d[2])); @@ -931,7 +931,7 @@ void vec3f_to_vec3s_get_dist_and_angle(Vec3f from, Vec3s to, f32 *dist, Angle *p } /// Finds the distance, horizontal distance, and angles between two vectors. -void vec3f_get_dist_and_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, f32 *lateralDist, Angle *pitch, Angle *yaw) { +void vec3f_get_dist_and_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, f32 *lateralDist, s16 *pitch, s16 *yaw) { Vec3f d; vec3_diff(d, to, from); register f32 xz = (sqr(d[0]) + sqr(d[2])); @@ -951,17 +951,17 @@ void vec3f_get_dist_and_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, to[1] = (from[1] + (dist * sins(pitch))); \ to[2] = (from[2] + (dcos * coss(yaw ))); \ } -void vec3f_set_dist_and_angle(Vec3f from, Vec3f to, f32 dist, Angle32 pitch, Angle32 yaw) { +void vec3f_set_dist_and_angle(Vec3f from, Vec3f to, f32 dist, s16 pitch, s16 yaw) { vec3_set_dist_and_angle(from, to, dist, pitch, yaw); } -void vec3s_set_dist_and_angle(Vec3s from, Vec3s to, s16 dist, Angle32 pitch, Angle32 yaw) { +void vec3s_set_dist_and_angle(Vec3s from, Vec3s to, s16 dist, s16 pitch, s16 yaw) { vec3_set_dist_and_angle(from, to, dist, pitch, yaw); } /** * Similar to approach_s32, but converts to s16 and allows for overflow between 32767 and -32768 */ -s32 approach_angle(s32 current, s32 target, s32 inc) { +s16 approach_angle(s16 current, s16 target, s16 inc) { s32 dist = (s16)(target - current); if (dist < 0) { dist += inc; @@ -972,21 +972,21 @@ s32 approach_angle(s32 current, s32 target, s32 inc) { } return (target - dist); } -Bool32 approach_angle_bool(s16 *current, s32 target, s32 inc) { +Bool32 approach_angle_bool(s16 *current, s16 target, s16 inc) { *current = approach_angle(*current, target, inc); return (*current != target); } -s32 approach_s16(s32 current, s32 target, s32 inc, s32 dec) { +s16 approach_s16(s16 current, s16 target, s16 inc, s16 dec) { s16 dist = (target - current); if (dist >= 0) { // target >= current current = ((dist > inc) ? (current + inc) : target); } else { // target < current current = ((dist < -dec) ? (current - dec) : target); } - return (s16)current; + return current; } -Bool32 approach_s16_bool(s16 *current, s32 target, s32 inc, s32 dec) { +Bool32 approach_s16_bool(s16 *current, s16 target, s16 inc, s16 dec) { *current = approach_s16(*current, target, inc, dec); return (*current != target); } @@ -1067,7 +1067,7 @@ f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier) { * is reached. Note: Since this function takes integers as parameters, the last argument is the * reciprocal of what it would be in the previous two functions. */ -s32 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor) { +s16 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor) { s16 temp = *current; if (divisor == 0) { *current = target; @@ -1084,7 +1084,7 @@ s32 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor) { * Approaches an s16 value in the same fashion as approach_f32_asymptotic, returns the new value. * Note: last parameter is the reciprocal of what it would be in the f32 functions */ -s32 approach_s16_asymptotic(s16 current, s16 target, s16 divisor) { +s16 approach_s16_asymptotic(s16 current, s16 target, s16 divisor) { s16 temp = current; if (divisor == 0) { current = target; @@ -1097,7 +1097,7 @@ s32 approach_s16_asymptotic(s16 current, s16 target, s16 divisor) { return current; } -s32 abs_angle_diff(s16 a0, s16 a1) { +s16 abs_angle_diff(s16 a0, s16 a1) { register s16 diff = (a1 - a0); if (diff == -0x8000) return 0x7FFF; return abss(diff); @@ -1107,7 +1107,7 @@ s32 abs_angle_diff(s16 a0, s16 a1) { * Helper function for atan2s. Does a look up of the arctangent of y/x assuming * the resulting angle is in range [0, 0x2000] (1/8 of a circle). */ -static u32 atan2_lookup(f32 y, f32 x) { +static u16 atan2_lookup(f32 y, f32 x) { return x == 0 ? 0x0 : atans(y / x); @@ -1117,7 +1117,7 @@ static u32 atan2_lookup(f32 y, f32 x) { * Compute the angle from (0, 0) to (x, y) as a s16. Given that terrain is in * the xz-plane, this is commonly called with (z, x) to get a yaw angle. */ -s32 atan2s(f32 y, f32 x) { +s16 atan2s(f32 y, f32 x) { u16 ret; if (x >= 0) { if (y >= 0) { diff --git a/src/engine/math_util.h b/src/engine/math_util.h index 2c131d1a..7637a6ab 100644 --- a/src/engine/math_util.h +++ b/src/engine/math_util.h @@ -54,12 +54,12 @@ extern f32 gSineTable[]; #define RAD_PER_DEG (M_PI / 180.0f) #define DEG_PER_RAD (180.0f / M_PI) -#define angle_to_degrees( x) (f32)(((Angle)(x) / 65536.0f) * 360.0f) -#define degrees_to_angle( x) (Angle)(((f32)(x) * 0x10000 ) / 360 ) -#define angle_to_radians( x) (f32)(((Angle)(x) * M_PI ) / 0x8000) -#define radians_to_angle( x) (Angle)(((f32)(x) / M_PI ) * 0x8000) -#define degrees_to_radians(x) (f32)( (f32)(x) * RAD_PER_DEG ) -#define radians_to_degrees(x) (f32)( (f32)(x) * DEG_PER_RAD ) +#define angle_to_degrees( x) (f32)(((s16)(x) / 65536.0f) * 360.0f) +#define degrees_to_angle( x) (s16)(((f32)(x) * 0x10000 ) / 360 ) +#define angle_to_radians( x) (f32)(((s16)(x) * M_PI ) / 0x8000) +#define radians_to_angle( x) (s16)(((f32)(x) / M_PI ) * 0x8000) +#define degrees_to_radians(x) (f32)( (f32)(x) * RAD_PER_DEG ) +#define radians_to_degrees(x) (f32)( (f32)(x) * DEG_PER_RAD ) #define signum_positive(x) ((x < 0) ? -1 : 1) @@ -538,15 +538,15 @@ void vec3f_normalize(Vec3f dest); void mtxf_copy(Mat4 dest, Mat4 src); void mtxf_identity(Mat4 mtx); void mtxf_translate(Mat4 dest, Vec3f b); -void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s32 roll); +void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s16 roll); void mtxf_rotate_zxy_and_translate(Mat4 dest, Vec3f trans, Vec3s rot); void mtxf_rotate_xyz_and_translate(Mat4 dest, Vec3f trans, Vec3s rot); void mtxf_rotate_zxy_and_translate_and_mul(Vec3s rot, Vec3f trans, Mat4 dest, Mat4 src); void mtxf_rotate_xyz_and_translate_and_mul(Vec3s rot, Vec3f trans, Mat4 dest, Mat4 src); -void mtxf_billboard(Mat4 dest, Mat4 mtx, Vec3f position, Vec3f scale, s32 angle); -void mtxf_shadow(Mat4 dest, Mat4 src, Vec3f upDir, Vec3f pos, Vec3f scale, s32 yaw); -void mtxf_align_terrain_normal(Mat4 dest, Vec3f upDir, Vec3f pos, s32 yaw); -void mtxf_align_terrain_triangle(Mat4 mtx, Vec3f pos, s32 yaw, f32 radius); +void mtxf_billboard(Mat4 dest, Mat4 mtx, Vec3f position, Vec3f scale, s16 angle); +void mtxf_shadow(Mat4 dest, Mat4 src, Vec3f upDir, Vec3f pos, Vec3f scale, s16 yaw); +void mtxf_align_terrain_normal(Mat4 dest, Vec3f upDir, Vec3f pos, s16 yaw); +void mtxf_align_terrain_triangle(Mat4 mtx, Vec3f pos, s16 yaw, f32 radius); void mtxf_mul(Mat4 dest, Mat4 a, Mat4 b); void mtxf_scale_vec3f(Mat4 dest, Mat4 mtx, Vec3f s); void mtxf_mul_vec3s(Mat4 mtx, Vec3s b); @@ -557,37 +557,37 @@ ALWAYS_INLINE void mtxf_to_mtx(register void *dest, register void *src) { // guMtxF2L(src, dest); } -void mtxf_rotate_xy(Mtx *mtx, s32 angle); +void mtxf_rotate_xy(Mtx *mtx, s16 angle); void linear_mtxf_mul_vec3f(Mat4 m, Vec3f dst, Vec3f v); void linear_mtxf_mul_vec3f_and_translate(Mat4 m, Vec3f dst, Vec3f v); void linear_mtxf_transpose_mul_vec3f(Mat4 m, Vec3f dst, Vec3f v); void get_pos_from_transform_mtx(Vec3f dest, Mat4 objMtx, Mat4 camMtx); -void vec2f_get_lateral_dist( Vec2f from, Vec2f to, f32 *lateralDist ); -void vec3f_get_lateral_dist( Vec3f from, Vec3f to, f32 *lateralDist ); -void vec3f_get_lateral_dist_squared( Vec3f from, Vec3f to, f32 *lateralDist ); -void vec3f_get_dist( Vec3f from, Vec3f to, f32 *dist ); -void vec3f_get_dist_squared( Vec3f from, Vec3f to, f32 *dist ); -void vec3f_get_dist_and_yaw( Vec3f from, Vec3f to, f32 *dist, Angle *yaw); -void vec3f_get_pitch( Vec3f from, Vec3f to, Angle *pitch ); -void vec3f_get_yaw( Vec3f from, Vec3f to, Angle *yaw); -void vec3f_get_angle( Vec3f from, Vec3f to, Angle *pitch, Angle *yaw); -void vec3f_get_lateral_dist_and_pitch( Vec3f from, Vec3f to, f32 *lateralDist, Angle *pitch ); -void vec3f_get_lateral_dist_and_yaw( Vec3f from, Vec3f to, f32 *lateralDist, Angle *yaw); -void vec3f_get_lateral_dist_and_angle( Vec3f from, Vec3f to, f32 *lateralDist, Angle *pitch, Angle *yaw); -void vec3f_get_dist_and_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, f32 *lateralDist, Angle *pitch, Angle *yaw); -void vec3f_get_dist_and_angle( Vec3f from, Vec3f to, f32 *dist, Angle *pitch, Angle *yaw); -void vec3s_get_dist_and_angle( Vec3s from, Vec3s to, s16 *dist, Angle *pitch, Angle *yaw); -void vec3f_to_vec3s_get_dist_and_angle( Vec3f from, Vec3s to, f32 *dist, Angle *pitch, Angle *yaw); -void vec3s_set_dist_and_angle( Vec3s from, Vec3s to, s16 dist, Angle32 pitch, Angle32 yaw); -void vec3f_set_dist_and_angle( Vec3f from, Vec3f to, f32 dist, Angle32 pitch, Angle32 yaw); +void vec2f_get_lateral_dist( Vec2f from, Vec2f to, f32 *lateralDist ); +void vec3f_get_lateral_dist( Vec3f from, Vec3f to, f32 *lateralDist ); +void vec3f_get_lateral_dist_squared( Vec3f from, Vec3f to, f32 *lateralDist ); +void vec3f_get_dist( Vec3f from, Vec3f to, f32 *dist ); +void vec3f_get_dist_squared( Vec3f from, Vec3f to, f32 *dist ); +void vec3f_get_dist_and_yaw( Vec3f from, Vec3f to, f32 *dist, s16 *yaw); +void vec3f_get_pitch( Vec3f from, Vec3f to, s16 *pitch ); +void vec3f_get_yaw( Vec3f from, Vec3f to, s16 *yaw); +void vec3f_get_angle( Vec3f from, Vec3f to, s16 *pitch, s16 *yaw); +void vec3f_get_lateral_dist_and_pitch( Vec3f from, Vec3f to, f32 *lateralDist, s16 *pitch ); +void vec3f_get_lateral_dist_and_yaw( Vec3f from, Vec3f to, f32 *lateralDist, s16 *yaw); +void vec3f_get_lateral_dist_and_angle( Vec3f from, Vec3f to, f32 *lateralDist, s16 *pitch, s16 *yaw); +void vec3f_get_dist_and_lateral_dist_and_angle(Vec3f from, Vec3f to, f32 *dist, f32 *lateralDist, s16 *pitch, s16 *yaw); +void vec3f_get_dist_and_angle( Vec3f from, Vec3f to, f32 *dist, s16 *pitch, s16 *yaw); +void vec3s_get_dist_and_angle( Vec3s from, Vec3s to, s16 *dist, s16 *pitch, s16 *yaw); +void vec3f_to_vec3s_get_dist_and_angle( Vec3f from, Vec3s to, f32 *dist, s16 *pitch, s16 *yaw); +void vec3s_set_dist_and_angle( Vec3s from, Vec3s to, s16 dist, s16 pitch, s16 yaw); +void vec3f_set_dist_and_angle( Vec3f from, Vec3f to, f32 dist, s16 pitch, s16 yaw); -s32 approach_angle(s32 current, s32 target, s32 inc); -s32 approach_s16(s32 current, s32 target, s32 inc, s32 dec); +s16 approach_angle(s16 current, s16 target, s16 inc); +s16 approach_s16(s16 current, s16 target, s16 inc, s16 dec); s32 approach_s32(s32 current, s32 target, s32 inc, s32 dec); f32 approach_f32(f32 current, f32 target, f32 inc, f32 dec); -Bool32 approach_angle_bool(s16 *current, s32 target, s32 inc); -Bool32 approach_s16_bool(s16 *current, s32 target, s32 inc, s32 dec); +Bool32 approach_angle_bool(s16 *current, s16 target, s16 inc); +Bool32 approach_s16_bool(s16 *current, s16 target, s16 inc, s16 dec); Bool32 approach_s32_bool(s32 *current, s32 target, s32 inc, s32 dec); Bool32 approach_f32_bool(f32 *current, f32 target, f32 inc, f32 dec); #define approach_s16_symmetric(current, target, inc) approach_s16((current), (target), (inc), (inc)) @@ -599,10 +599,10 @@ Bool32 approach_f32_bool(f32 *current, f32 target, f32 inc, f32 dec); s32 approach_f32_signed(f32 *current, f32 target, f32 inc); s32 approach_f32_asymptotic_bool(f32 *current, f32 target, f32 multiplier); f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier); -s32 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor); -s32 approach_s16_asymptotic(s16 current, s16 target, s16 divisor); -s32 abs_angle_diff(s16 a0, s16 a1); -s32 atan2s(f32 y, f32 x); +s16 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor); +s16 approach_s16_asymptotic(s16 current, s16 target, s16 divisor); +s16 abs_angle_diff(s16 a0, s16 a1); +s16 atan2s(f32 y, f32 x); f32 atan2f(f32 a, f32 b); void spline_get_weights(Vec4f result, f32 t, UNUSED s32 c); void anim_spline_init(Vec4s *keyFrames); diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 2e5f67d7..29dc2ff7 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -429,7 +429,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 height = get_surface_height_at_location(x, z, surf); // Exclude floors lower than the previous highest floor. - if (height < *pheight) continue; + if (height <= *pheight) continue; // Checks for floor interaction with a FIND_FLOOR_BUFFER unit buffer. if (bufferY < height) continue; diff --git a/src/game/behaviors/boo.inc.c b/src/game/behaviors/boo.inc.c index 316f8f27..9a638c76 100644 --- a/src/game/behaviors/boo.inc.c +++ b/src/game/behaviors/boo.inc.c @@ -178,7 +178,7 @@ static void boo_set_move_yaw_for_during_hit(s32 hurt) { } // Boo Roll -static Angle sBooHitRotations[] = { +static s16 sBooHitRotations[] = { 0x179F, 0x1620, 0x14AC, 0x1346, 0x11EB, 0x109E, 0x0B75, 0x0E28, 0x0D01, 0x0BE6, 0x0AD7, 0x09D5, diff --git a/src/game/behaviors/hoot.inc.c b/src/game/behaviors/hoot.inc.c index 0fa0ca98..942a839c 100644 --- a/src/game/behaviors/hoot.inc.c +++ b/src/game/behaviors/hoot.inc.c @@ -68,7 +68,7 @@ void hoot_free_step(s16 fastOscY, s32 speed) { void hoot_player_set_yaw(void) { #ifdef HOOT_YAW_FIX - Angle turnSpeed = gMarioState->intendedMag * 0x20; + s16 turnSpeed = gMarioState->intendedMag * 0x20; o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, gMarioState->intendedYaw, turnSpeed); #else s16 stickX = gPlayer3Controller->rawStickX; @@ -193,7 +193,7 @@ void hoot_action_loop(void) { } void hoot_turn_to_home(void) { - Angle pitchToHome, yawToHome; + s16 pitchToHome, yawToHome; vec3f_get_angle(&o->oPosVec, &o->oHomeVec, &pitchToHome, &yawToHome); o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, yawToHome, 0x140); diff --git a/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c b/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c index 5477e957..19d0e8b8 100644 --- a/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c +++ b/src/game/behaviors/lll_octagonal_rotating_mesh.inc.c @@ -8,10 +8,10 @@ enum LLLOctagonalMeshInstructions { }; struct LllOctagonalMeshAction { - s16 instruction; - s16 time; - Angle moveAngle; - s16 forwardVel; + s16 instruction; + s16 time; + s16 moveAngle; + s16 forwardVel; }; // Path for big bullies platforms diff --git a/src/game/behaviors/platform_on_track.inc.c b/src/game/behaviors/platform_on_track.inc.c index 65a0fd8e..beb1a467 100644 --- a/src/game/behaviors/platform_on_track.inc.c +++ b/src/game/behaviors/platform_on_track.inc.c @@ -384,7 +384,7 @@ void bhv_platform_on_track_update(void) { platform_on_track_rock_ski_lift(); } else if (o->oPlatformOnTrackType == PLATFORM_ON_TRACK_TYPE_CARPET) { #ifdef CONTROLLABLE_PLATFORM_SPEED - Angle targetRoll; // Visually, this is the platform's pitch, since these platforms technically move sideways + s16 targetRoll; // Visually, this is the platform's pitch, since these platforms technically move sideways if (gMarioObject->platform == o) { if (!o->oPlatformOnTrackWasStoodOn) { o->oPlatformOnTrackOffsetY = -8.0f; diff --git a/src/game/behaviors/spawn_star.inc.c b/src/game/behaviors/spawn_star.inc.c index 4cdfda57..665629af 100644 --- a/src/game/behaviors/spawn_star.inc.c +++ b/src/game/behaviors/spawn_star.inc.c @@ -39,7 +39,7 @@ void bhv_collect_star_loop(void) { } void bhv_star_spawn_init(void) { - Angle yaw; + s16 yaw; vec3f_get_lateral_dist_and_yaw(&o->oPosVec, &o->oHomeVec, &o->oStarSpawnDisFromHome, &yaw); o->oMoveAngleYaw = yaw; o->oVelY = (o->oHomeY - o->oPosY) / 30.0f; diff --git a/src/game/camera.c b/src/game/camera.c index 21d40773..f9bf782c 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -4257,7 +4257,7 @@ s32 is_pos_in_bounds(Vec3f pos, Vec3f center, Vec3f bounds, s16 boundsYaw) { -bounds[2] < rel[2] && rel[2] < bounds[2]); } -s32 calculate_pitch(Vec3f from, Vec3f to) { +s16 calculate_pitch(Vec3f from, Vec3f to) { f32 dx = to[0] - from[0]; f32 dy = to[1] - from[1]; f32 dz = to[2] - from[2]; @@ -4266,7 +4266,7 @@ s32 calculate_pitch(Vec3f from, Vec3f to) { return pitch; } -s32 calculate_yaw(Vec3f from, Vec3f to) { +s16 calculate_yaw(Vec3f from, Vec3f to) { f32 dx = to[0] - from[0]; // UNUSED f32 dy = to[1] - from[1]; f32 dz = to[2] - from[2]; diff --git a/src/game/camera.h b/src/game/camera.h index 23872607..fcd1f59f 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -750,8 +750,8 @@ void random_vec3s(Vec3s dst, s16 xRange, s16 yRange, s16 zRange); s32 clamp_positions_and_find_yaw(Vec3f pos, Vec3f origin, f32 xMax, f32 xMin, f32 zMax, f32 zMin); s32 is_range_behind_surface(Vec3f from, Vec3f to, struct Surface *surf, s16 range, s16 surfType); void scale_along_line(Vec3f dest, Vec3f from, Vec3f to, f32 scale); -s32 calculate_pitch(Vec3f from, Vec3f to); -s32 calculate_yaw(Vec3f from, Vec3f to); +s16 calculate_pitch(Vec3f from, Vec3f to); +s16 calculate_yaw(Vec3f from, Vec3f to); void calculate_angles(Vec3f from, Vec3f to, s16 *pitch, s16 *yaw); f32 calc_abs_dist(Vec3f a, Vec3f b); f32 calc_abs_dist_squared(Vec3f a, Vec3f b); diff --git a/src/game/macro_special_objects.c b/src/game/macro_special_objects.c index a00b6c82..458ba2a1 100644 --- a/src/game/macro_special_objects.c +++ b/src/game/macro_special_objects.c @@ -78,7 +78,7 @@ UNUSED static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 } struct LoadedMacroObject { - /*0x00*/ Angle yaw; + /*0x00*/ s16 yaw; /*0x02*/ Vec3s pos; /*0x08*/ s16 params; }; diff --git a/src/game/skybox.c b/src/game/skybox.c index 1cc599f9..ded26eb3 100644 --- a/src/game/skybox.c +++ b/src/game/skybox.c @@ -217,6 +217,10 @@ void draw_skybox_tile_grid(Gfx **dlist, s8 background, s8 player, s8 colorIndex) for (row = 0; row < (3 * SKYBOX_SIZE); row++) { for (col = 0; col < (3 * SKYBOX_SIZE); col++) { s32 tileIndex = sSkyBoxInfo[player].upperLeftTile + row * SKYBOX_COLS + col; + if (tileIndex >= SKYBOX_ROWS * SKYBOX_COLS) { + continue; + } + const Texture *const texture = (*(SkyboxTexture *) segmented_to_virtual(sSkyboxTextures[background]))[tileIndex]; Vtx *vertices = make_skybox_rect(tileIndex, colorIndex); From efd4e3f9dc3e8f8636e79ed51df019d05b95b871 Mon Sep 17 00:00:00 2001 From: axollyon <20480418+axollyon@users.noreply.github.com> Date: Wed, 23 Nov 2022 20:46:09 -0500 Subject: [PATCH 04/13] Update VERSION.txt (#534) --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 8a5b818b..c2f6de90 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -v2.0.4 +v2.0.5 From dc1a824ce9a80875d08c79c5c03d99186d906142 Mon Sep 17 00:00:00 2001 From: Gregory Heskett Date: Sun, 4 Dec 2022 05:05:59 -0500 Subject: [PATCH 05/13] HackerSM64 2.0.6 (#539) * revert random_u16 to be a u16 (#538) * Added safety gcc math flags (#537) * removed useless compilation flags that could cause performance loss Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com> Co-authored-by: thecozies --- Makefile | 13 +++++++++---- src/engine/math_util.c | 2 +- src/engine/math_util.h | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 977d2a2c..9fd0e28b 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,7 @@ LINK_LIBRARIES = $(foreach i,$(LIBRARIES),-l$(i)) # Default non-gcc opt flags DEFAULT_OPT_FLAGS = -Ofast +SAFETY_OPT_FLAGS = -ftrapping-math # Main opt flags GCC_MAIN_OPT_FLAGS = \ @@ -145,7 +146,8 @@ GCC_MAIN_OPT_FLAGS = \ -finline-limit=1 \ -freorder-blocks-algorithm=simple \ -ffunction-sections \ - -fdata-sections + -fdata-sections \ + $(SAFETY_OPT_FLAGS) # Surface Collision GCC_COLLISION_OPT_FLAGS = \ @@ -158,7 +160,8 @@ GCC_COLLISION_OPT_FLAGS = \ -freorder-blocks-algorithm=simple \ -ffunction-sections \ -fdata-sections \ - -falign-functions=32 + -falign-functions=32 \ + $(SAFETY_OPT_FLAGS) # Math Util GCC_MATH_UTIL_OPT_FLAGS = \ @@ -168,7 +171,8 @@ GCC_MATH_UTIL_OPT_FLAGS = \ --param case-values-threshold=20 \ -ffunction-sections \ -fdata-sections \ - -falign-functions=32 + -falign-functions=32 \ + $(SAFETY_OPT_FLAGS) # - setting any sort of -finline-limit has shown to worsen performance with math_util.c, # lower values were the worst, the higher you go - the closer performance gets to not setting it at all @@ -182,7 +186,8 @@ GCC_GRAPH_NODE_OPT_FLAGS = \ -freorder-blocks-algorithm=simple \ -ffunction-sections \ -fdata-sections \ - -falign-functions=32 + -falign-functions=32 \ + $(SAFETY_OPT_FLAGS) #==============================================================================# ifeq ($(COMPILER),gcc) diff --git a/src/engine/math_util.c b/src/engine/math_util.c index db043e95..fe53d59c 100644 --- a/src/engine/math_util.c +++ b/src/engine/math_util.c @@ -28,7 +28,7 @@ Vec3s gVec3sOne = { 1, 1, 1 }; static u16 gRandomSeed16; // Generate a pseudorandom integer from 0 to 65535 from the random seed, and update the seed. -u32 random_u16(void) { +u16 random_u16(void) { if (gRandomSeed16 == 22026) { gRandomSeed16 = 0; } diff --git a/src/engine/math_util.h b/src/engine/math_util.h index 7637a6ab..2cdbaa3d 100644 --- a/src/engine/math_util.h +++ b/src/engine/math_util.h @@ -475,7 +475,7 @@ ALWAYS_INLINE s32 absi(s32 in) { #define FLT_IS_NONZERO(x) (absf(x) > NEAR_ZERO) -u32 random_u16(void); +u16 random_u16(void); f32 random_float(void); s32 random_sign(void); From d3d2bb9247a16e24d117f40404e77557d8421457 Mon Sep 17 00:00:00 2001 From: axollyon <20480418+axollyon@users.noreply.github.com> Date: Sun, 4 Dec 2022 05:50:20 -0500 Subject: [PATCH 06/13] Update VERSION.txt HackerSM64 2.0.6 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index c2f6de90..cea0e158 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -v2.0.5 +v2.0.6 From e3e1aa02ac2f4427ca9029a4dfc11b200ad1a436 Mon Sep 17 00:00:00 2001 From: thecozies Date: Mon, 5 Dec 2022 08:36:32 -0600 Subject: [PATCH 07/13] Add GCC opt flag to suppress warnings --- Makefile | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 9fd0e28b..a19bd4e2 100644 --- a/Makefile +++ b/Makefile @@ -135,23 +135,25 @@ LINK_LIBRARIES = $(foreach i,$(LIBRARIES),-l$(i)) # Default non-gcc opt flags DEFAULT_OPT_FLAGS = -Ofast -SAFETY_OPT_FLAGS = -ftrapping-math +# Note: -fno-associative-math is used here to suppress warnings, ideally we would enable this as an optimization but +# this conflicts with -ftrapping-math apparently. +# TODO: Figure out how to allow -fassociative-math to be enabled +SAFETY_OPT_FLAGS = -ftrapping-math -fno-associative-math # Main opt flags GCC_MAIN_OPT_FLAGS = \ - -Ofast \ + $(DEFAULT_OPT_FLAGS) $(SAFETY_OPT_FLAGS) \ --param case-values-threshold=20 \ --param max-completely-peeled-insns=10 \ --param max-unrolled-insns=10 \ -finline-limit=1 \ -freorder-blocks-algorithm=simple \ -ffunction-sections \ - -fdata-sections \ - $(SAFETY_OPT_FLAGS) + -fdata-sections # Surface Collision GCC_COLLISION_OPT_FLAGS = \ - -Ofast \ + $(DEFAULT_OPT_FLAGS) $(SAFETY_OPT_FLAGS) \ --param case-values-threshold=20 \ --param max-completely-peeled-insns=100 \ --param max-unrolled-insns=100 \ @@ -160,25 +162,23 @@ GCC_COLLISION_OPT_FLAGS = \ -freorder-blocks-algorithm=simple \ -ffunction-sections \ -fdata-sections \ - -falign-functions=32 \ - $(SAFETY_OPT_FLAGS) + -falign-functions=32 # Math Util GCC_MATH_UTIL_OPT_FLAGS = \ - -Ofast \ + $(DEFAULT_OPT_FLAGS) $(SAFETY_OPT_FLAGS) \ -fno-unroll-loops \ -fno-peel-loops \ --param case-values-threshold=20 \ -ffunction-sections \ -fdata-sections \ - -falign-functions=32 \ - $(SAFETY_OPT_FLAGS) + -falign-functions=32 # - setting any sort of -finline-limit has shown to worsen performance with math_util.c, # lower values were the worst, the higher you go - the closer performance gets to not setting it at all # Rendering graph node GCC_GRAPH_NODE_OPT_FLAGS = \ - -Ofast \ + $(DEFAULT_OPT_FLAGS) $(SAFETY_OPT_FLAGS) \ --param case-values-threshold=20 \ --param max-completely-peeled-insns=100 \ --param max-unrolled-insns=100 \ @@ -186,8 +186,7 @@ GCC_GRAPH_NODE_OPT_FLAGS = \ -freorder-blocks-algorithm=simple \ -ffunction-sections \ -fdata-sections \ - -falign-functions=32 \ - $(SAFETY_OPT_FLAGS) + -falign-functions=32 #==============================================================================# ifeq ($(COMPILER),gcc) From e87dfa74d82887bb56bbcac52bcdc5ee45f9e847 Mon Sep 17 00:00:00 2001 From: thecozies Date: Mon, 5 Dec 2022 08:39:28 -0600 Subject: [PATCH 08/13] v2.0.7 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index cea0e158..d8ba80f9 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -v2.0.6 +v2.0.7 From 7ef2077353c86a552692150cf35a0c6d21d5a361 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Tue, 6 Dec 2022 15:41:55 -0500 Subject: [PATCH 09/13] 2.0.8 (fix more compiler warnings) (#543) * fix Waddress in mario_step.c * fix Winfinite-recursion in unused dynlist_proc function * in fact remove the offending function entirely * fix warnings in RNC decompress functions * update version * fix version in VERSION.txt premature on my part, will update it to 2.0.10 next time Co-authored-by: someone2639 --- VERSION.txt | 2 +- src/boot/rnc1.s | 2 +- src/boot/rnc2.s | 6 +++--- src/game/mario_step.c | 2 +- src/goddard/dynlist_proc.c | 41 -------------------------------------- 5 files changed, 6 insertions(+), 47 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index d8ba80f9..923fd4d2 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -v2.0.7 +v2.0.8 diff --git a/src/boot/rnc1.s b/src/boot/rnc1.s index 0234a7e8..1101c1f7 100755 --- a/src/boot/rnc1.s +++ b/src/boot/rnc1.s @@ -412,4 +412,4 @@ make_huftable8: jr ra nop /*(Delay Slot) */ - .end +.end Propack_UnpackM1 diff --git a/src/boot/rnc2.s b/src/boot/rnc2.s index d3a2ca94..e3397e3c 100755 --- a/src/boot/rnc2.s +++ b/src/boot/rnc2.s @@ -663,11 +663,11 @@ unpack11: jr ra nop - .data +.end Propack_UnpackM2 + +.data .align 4 .word 0,0,0,0,0,0,0,0,0,0,0,0 mystack: .word 0 - - .end diff --git a/src/game/mario_step.c b/src/game/mario_step.c index eb9923fd..028d4962 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -541,7 +541,7 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr } } - if (stepResult == AIR_STEP_GRABBED_LEDGE && grabbedWall != NULL && ledgeFloor != NULL && ledgePos != NULL) { + if (stepResult == AIR_STEP_GRABBED_LEDGE && grabbedWall != NULL && ledgeFloor != NULL) { vec3f_copy(m->pos, ledgePos); set_mario_floor(m, floor, ledgePos[1]); m->faceAngle[0] = 0x0; diff --git a/src/goddard/dynlist_proc.c b/src/goddard/dynlist_proc.c index 82ddae28..12bd613f 100644 --- a/src/goddard/dynlist_proc.c +++ b/src/goddard/dynlist_proc.c @@ -1895,47 +1895,6 @@ void d_set_att_offset(const struct GdVec3f *off) { } } -/** - * An incorrectly-coded recursive function that was presumably supposed to - * set the offset of an attached object. Now, it will only call itself - * until it encounters a NULL pointer, which will trigger a `fatal_printf()` - * call. - * - * @note Not called - */ -void d_set_att_to_offset(UNUSED u32 a) { - struct GdObj *dynobj; // sp3c - UNUSED u8 filler[24]; - - if (sDynListCurObj == NULL) { - fatal_printf("proc_dynlist(): No current object"); - } - - dynobj = sDynListCurObj; - d_stash_dynobj(); - switch (sDynListCurObj->type) { - case OBJ_TYPE_JOINTS: - set_cur_dynobj(((struct ObjJoint *) dynobj)->attachedToObj); - break; - case OBJ_TYPE_NETS: - set_cur_dynobj(((struct ObjNet *) dynobj)->attachedToObj); - break; - case OBJ_TYPE_PARTICLES: - set_cur_dynobj(((struct ObjParticle *) dynobj)->attachedToObj); - break; - default: - fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetAttToOffset()", - sDynListCurInfo->name, sDynListCurObj->type); - } - - if (sDynListCurObj == NULL) { - fatal_printf("dSetAttOffset(): Object '%s' isnt attached to anything", - sStashedDynObjInfo->name); - } - d_set_att_to_offset(a); - d_unstash_dynobj(); -} - /** * Store the offset of the attached object into `dst`. * From d68233a1c0df5cdb4bbd04b3dfad245284a8c623 Mon Sep 17 00:00:00 2001 From: thecozies Date: Fri, 5 May 2023 11:16:57 -0500 Subject: [PATCH 10/13] Aligned gfx buffers to 32 --- src/buffers/buffers.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/buffers/buffers.c b/src/buffers/buffers.c index 5d382702..f231ca8b 100644 --- a/src/buffers/buffers.c +++ b/src/buffers/buffers.c @@ -20,14 +20,8 @@ ALIGNED8 u8 gThread5Stack[0x2000]; ALIGNED8 u8 gThread6Stack[0x2000]; #endif // 0x400 bytes -#if UNF -ALIGNED16 u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8]; -ALIGNED16 u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE]; -#else -// 0xc00 bytes for f3dex, 0x900 otherwise -ALIGNED8 u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8]; -ALIGNED8 u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE]; -#endif // UNF +__attribute__((aligned(32))) u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8]; +__attribute__((aligned(32))) u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE]; // 0x200 bytes struct SaveBuffer __attribute__ ((aligned (8))) gSaveBuffer; // 0x190a0 bytes From 312496d769b70b6fbd531b87925fcd69b1dddadf Mon Sep 17 00:00:00 2001 From: thecozies Date: Wed, 12 Apr 2023 18:07:49 -0500 Subject: [PATCH 11/13] copied new unf usb lib --- src/usb/debug.c | 176 ++++-- src/usb/debug.h | 17 +- src/usb/usb.c | 1470 ++++++++++++++++++++++------------------------- src/usb/usb.h | 94 +-- 4 files changed, 871 insertions(+), 886 deletions(-) diff --git a/src/usb/debug.c b/src/usb/debug.c index e6bd4e94..f112db9a 100644 --- a/src/usb/debug.c +++ b/src/usb/debug.c @@ -18,7 +18,6 @@ https://github.com/buu342/N64-UNFLoader #include - #if DEBUG_MODE /********************************* @@ -39,39 +38,41 @@ https://github.com/buu342/N64-UNFLoader #define COMMAND_TOKENS 10 #define BUFFER_SIZE 256 + /********************************* - Libultra types (for libdragon) + Libultra types (for libdragon) *********************************/ - + #ifdef LIBDRAGON typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; typedef unsigned long long u64; - + typedef signed char s8; typedef short s16; typedef long s32; typedef long long s64; - + typedef volatile unsigned char vu8; typedef volatile unsigned short vu16; typedef volatile unsigned long vu32; typedef volatile unsigned long long vu64; - + typedef volatile signed char vs8; typedef volatile short vs16; typedef volatile long vs32; typedef volatile long long vs64; - + typedef float f32; typedef double f64; #endif + /********************************* Structs *********************************/ - + // Register struct typedef struct { @@ -109,7 +110,7 @@ https://github.com/buu342/N64-UNFLoader static void debug_thread_fault(void *arg); #endif static void debug_thread_usb(void *arg); - + // Other #if OVERWRITE_OSPRINT static void* debug_osSyncPrintf_implementation(void *unused, const char *str, size_t len); @@ -117,12 +118,13 @@ https://github.com/buu342/N64-UNFLoader #else static void debug_thread_usb(void *arg); #endif + static inline void debug_handle_64drivebutton(); /********************************* Globals *********************************/ - + // Function pointers #ifndef LIBDRAGON extern int _Printf(void *(*copyfunc)(void *, const char *, size_t), void*, const char*, va_list); @@ -130,7 +132,7 @@ https://github.com/buu342/N64-UNFLoader extern void* __printfunc; #endif #endif - + // Debug globals static char debug_initialized = 0; static char debug_buffer[BUFFER_SIZE]; @@ -138,20 +140,25 @@ https://github.com/buu342/N64-UNFLoader // Commands hashtable related static debugCommand* debug_commands_hashtable[HASHTABLE_SIZE]; static debugCommand debug_commands_elements[MAX_COMMANDS]; - static int debug_commands_count = 0; + static int debug_commands_count = 0; // Command parsing related - static int debug_command_current = 0; - static int debug_command_totaltokens = 0; - static int debug_command_incoming_start[COMMAND_TOKENS]; - static int debug_command_incoming_size[COMMAND_TOKENS]; - static char* debug_command_error; - + static int debug_command_current = 0; + static int debug_command_totaltokens = 0; + static int debug_command_incoming_start[COMMAND_TOKENS]; + static int debug_command_incoming_size[COMMAND_TOKENS]; + static char* debug_command_error = NULL; + // Assertion globals - static int assert_line = 0; + static int assert_line = 0; static const char* assert_file = NULL; static const char* assert_expr = NULL; - + + // 64Drive button functions + static void (*debug_64dbut_func)() = NULL; + static u64 debug_64dbut_debounce = 0; + static u64 debug_64dbut_hold = 0; + #ifndef LIBDRAGON // Fault thread globals #if USE_FAULTTHREAD @@ -166,7 +173,7 @@ https://github.com/buu342/N64-UNFLoader static OSMesg usbMessageBuf; static OSThread usbThread; static u64 usbThreadStack[USB_THREAD_STACK/sizeof(u64)]; - + // List of error causes static regDesc causeDesc[] = { {CAUSE_BD, CAUSE_BD, "BD"}, @@ -198,7 +205,7 @@ https://github.com/buu342/N64-UNFLoader {CAUSE_EXCMASK, EXC_VCED, "Virtual coherency exception on data reference"}, {0, 0, ""} }; - + // List of register descriptions static regDesc srDesc[] = { {SR_CU3, SR_CU3, "CU3"}, @@ -233,7 +240,7 @@ https://github.com/buu342/N64-UNFLoader {SR_IE, SR_IE, "IE"}, {0, 0, ""} }; - + // List of floating point registers descriptions static regDesc fpcsrDesc[] = { {FPCSR_FS, FPCSR_FS, "FS"}, @@ -261,7 +268,8 @@ https://github.com/buu342/N64-UNFLoader {0, 0, ""} }; #endif - + + /********************************* Debug functions *********************************/ @@ -276,7 +284,7 @@ https://github.com/buu342/N64-UNFLoader // Initialize the USB functions if (!usb_initialize()) return; - + // Overwrite osSyncPrintf #ifndef LIBDRAGON #if OVERWRITE_OSPRINT @@ -409,7 +417,7 @@ https://github.com/buu342/N64-UNFLoader // Ensure debug mode is initialized if (!debug_initialized) return; - + // Create the data header to send data[0] = DATATYPE_SCREENSHOT; data[1] = depth; @@ -426,7 +434,7 @@ https://github.com/buu342/N64-UNFLoader #else debug_thread_usb(&msg); #endif - + // Send the framebuffer to the USB thread msg.msgtype = MSG_WRITE; msg.datatype = DATATYPE_SCREENSHOT; @@ -438,8 +446,8 @@ https://github.com/buu342/N64-UNFLoader debug_thread_usb(&msg); #endif } - - + + /*============================== _debug_assert Halts the program (assumes expression failed) @@ -447,11 +455,9 @@ https://github.com/buu342/N64-UNFLoader @param The file where the exception ocurred @param The line number where the exception ocurred ==============================*/ - + void _debug_assert(const char* expression, const char* file, int line) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" volatile char crash; // Set the assert data @@ -463,10 +469,25 @@ https://github.com/buu342/N64-UNFLoader #ifdef LIBDRAGON debug_printf("Assertion failed in file '%s', line %d.\n", assert_file, assert_line); #endif - + // Intentionally cause a TLB exception on load/instruction fetch crash = *(volatile char *)1; -#pragma GCC diagnostic pop + (void)crash; + } + + + /*============================== + debug_64drivebutton + Assigns a function to be executed when the 64drive button is pressed. + @param The function pointer to execute + @param Whether or not to execute the function only on pressing (ignore holding the button down) + ==============================*/ + + void debug_64drivebutton(void(*execute)(), char onpress) + { + debug_64dbut_func = execute; + debug_64dbut_debounce = 0; + debug_64dbut_hold = !onpress; } @@ -549,7 +570,10 @@ https://github.com/buu342/N64-UNFLoader // Ensure debug mode is initialized if (!debug_initialized) return; - + + // Handle 64Drive button polling + debug_handle_64drivebutton(); + // Send a read message to the USB thread msg.msgtype = MSG_READ; #ifndef LIBDRAGON @@ -560,6 +584,56 @@ https://github.com/buu342/N64-UNFLoader } + /*============================== + debug_handle_64drivebutton + Handles the 64Drive's button logic + ==============================*/ + + static inline void debug_handle_64drivebutton() + { + static u32 held = 0; + + // If we own a 64Drive + if (usb_getcart() == CART_64DRIVE && debug_64dbut_func != NULL) + { + u64 curtime; + #ifndef LIBDRAGON + curtime = osGetTime(); + #else + curtime = timer_ticks(); + #endif + + // And the debounce time on the 64Drive's button has elapsed + if (debug_64dbut_debounce < curtime) + { + s32 bpoll; + #ifndef LIBDRAGON + osPiReadIo(0xB80002F8, (u32 *)&bpoll); + #else + bpoll = io_read(0xB80002F8); + #endif + bpoll = (bpoll&0xFFFF0000)>>16; + + // If the 64Drive's button has been pressed, then execute the assigned function and set the debounce timer + if (bpoll == 0 && (debug_64dbut_hold || !held)) + { + u64 nexttime; + #ifndef LIBDRAGON + nexttime = OS_USEC_TO_CYCLES(100000); + #else + nexttime = TIMER_TICKS(100000); + #endif + debug_64dbut_debounce = curtime + nexttime; + debug_64dbut_func(); + held = 1; + } + else if (bpoll != 0 && held) + held = 0; + } + } + } + + /*============================== debug_sizecommand Returns the size of the data from this part of the command @@ -606,7 +680,7 @@ https://github.com/buu342/N64-UNFLoader usb_rewind(debug_command_incoming_size[curr]+debug_command_incoming_start[curr]); debug_command_current++; } - + /*============================== debug_commands_setup @@ -631,11 +705,11 @@ https://github.com/buu342/N64-UNFLoader int readsize = BUFFER_SIZE; if (readsize > dataleft) readsize = dataleft; - + // Read a block from USB memset(debug_buffer, 0, BUFFER_SIZE); usb_read(debug_buffer, readsize); - + // Parse the block for (i=0; i 0; i++) { @@ -707,12 +781,12 @@ https://github.com/buu342/N64-UNFLoader Handles the USB thread @param Arbitrary data that the thread can receive ==============================*/ - + static void debug_thread_usb(void *arg) { char errortype = USBERROR_NONE; usbMesg* threadMsg; - + #ifndef LIBDRAGON // Create the message queue for the USB message osCreateMesgQueue(&usbMessageQ, &usbMessageBuf, 1); @@ -720,7 +794,7 @@ https://github.com/buu342/N64-UNFLoader // Set the received thread message to the argument threadMsg = (usbMesg*)arg; #endif - + // Thread loop while (1) { @@ -813,10 +887,12 @@ https://github.com/buu342/N64-UNFLoader switch (threadMsg->msgtype) { case MSG_WRITE: + if (usb_timedout()) + usb_sendheartbeat(); usb_write(threadMsg->datatype, threadMsg->buff, threadMsg->size); break; } - + // If we're in libdragon, break out of the loop as we don't need it #ifdef LIBDRAGON break; @@ -835,7 +911,7 @@ https://github.com/buu342/N64-UNFLoader @param The amount of characters to write @returns The end of the buffer that was written to ==============================*/ - + static void* debug_osSyncPrintf_implementation(void *unused, const char *str, size_t len) { void* ret; @@ -857,7 +933,7 @@ https://github.com/buu342/N64-UNFLoader } #endif - + #if USE_FAULTTHREAD /*============================== @@ -867,7 +943,7 @@ https://github.com/buu342/N64-UNFLoader @param The name of the register @param The registry description to use ==============================*/ - + static void debug_printreg(u32 value, char *name, regDesc *desc) { char first = 1; @@ -895,11 +971,11 @@ https://github.com/buu342/N64-UNFLoader { OSMesg msg; OSThread *curr; - + // Create the message queue for the fault message osCreateMesgQueue(&faultMessageQ, &faultMessageBuf, 1); osSetEventMesg(OS_EVENT_FAULT, &faultMessageQ, (OSMesg)MSG_FAULT); - + // Thread loop while (1) { @@ -911,7 +987,7 @@ https://github.com/buu342/N64-UNFLoader if (curr != NULL) { __OSThreadContext* context = &curr->context; - + // Print the basic info debug_printf("Fault in thread: %d\n\n", curr->id); debug_printf("pc\t\t0x%08x\n", context->pc); @@ -933,7 +1009,7 @@ https://github.com/buu342/N64-UNFLoader debug_printf("s6 0x%016llx s7 0x%016llx t8 0x%016llx\n", context->s6, context->s7, context->t8); debug_printf("t9 0x%016llx gp 0x%016llx sp 0x%016llx\n", context->t9, context->gp, context->sp); debug_printf("s8 0x%016llx ra 0x%016llx\n\n", context->s8, context->ra); - + // Print the floating point registers debug_printreg(context->fpcsr, "fpcsr", fpcsrDesc); debug_printf("\n"); @@ -952,4 +1028,4 @@ https://github.com/buu342/N64-UNFLoader #endif #endif -#endif \ No newline at end of file +#endif diff --git a/src/usb/debug.h b/src/usb/debug.h index ebe7ea69..5985ea17 100644 --- a/src/usb/debug.h +++ b/src/usb/debug.h @@ -77,6 +77,16 @@ #define debug_assert(expr) (expr) ? ((void)0) : _debug_assert(#expr, __FILE__, __LINE__) + /*============================== + debug_64drivebutton + Assigns a function to be executed when the 64drive button is pressed. + @param The function pointer to execute + @param Whether or not to execute the function only on pressing (ignore holding the button down) + ==============================*/ + + extern void debug_64drivebutton(void(*execute)(), char onpress); + + /*============================== debug_pollcommands Check the USB for incoming commands. @@ -90,7 +100,7 @@ Adds a command for the USB to read. @param The command name @param The command description - @param The function pointer to execute + @param The function pointer to execute ==============================*/ extern void debug_addcommand(char* command, char* description, char*(*execute)()); @@ -134,14 +144,15 @@ // Overwrite library functions with useless macros if debug mode is disabled #define debug_initialize() - #define debug_printf(__VA_ARGS__) + #define debug_printf #define debug_screenshot(a, b, c) #define debug_assert(a) #define debug_pollcommands() #define debug_addcommand(a, b, c) - #define debug_parsecommand() NULL + #define debug_parsecommand(a) NULL #define debug_sizecommand() 0 #define debug_printcommands() + #define debug_64drivebutton(a, b) #define usb_initialize() 0 #define usb_getcart() 0 #define usb_write(a, b, c) diff --git a/src/usb/usb.c b/src/usb/usb.c index 37becf01..f699bb47 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -23,11 +23,15 @@ https://github.com/buu342/N64-UNFLoader #define BUFFER_SIZE 512 // USB Memory location -#define DEBUG_ADDRESS 0x04000000-DEBUG_ADDRESS_SIZE // Put the debug area at the 63MB area in ROM space +#define DEBUG_ADDRESS (0x04000000 - DEBUG_ADDRESS_SIZE) // Put the debug area at the 64MB - DEBUG_ADDRESS_SIZE area in ROM space // Data header related #define USBHEADER_CREATE(type, left) (((type<<24) | (left & 0x00FFFFFF))) +// Protocol related +#define USBPROTOCOL_VERSION 2 +#define HEARTBEAT_VERSION 1 + /********************************* Libultra macros for libdragon @@ -35,8 +39,12 @@ https://github.com/buu342/N64-UNFLoader #ifdef LIBDRAGON // Useful - #define ALIGN(s, align) (((u32)(s) + ((align)-1)) & ~((align)-1)) - #define MIN(a, b) ((a) < (b) ? (a) : (b)) + #ifndef MIN + #define MIN(a, b) ((a) < (b) ? (a) : (b)) + #endif + #ifndef ALIGN + #define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1)) + #endif #ifndef TRUE #define TRUE 1 #endif @@ -52,150 +60,122 @@ https://github.com/buu342/N64-UNFLoader #define KSEG1 0xA0000000 // Memory translation stuff - #define PHYS_TO_K1(x) ((u32)(x)|KSEG1) - #define IO_WRITE(addr,data) (*(vu32 *)PHYS_TO_K1(addr)=(u32)(data)) - #define IO_READ(addr) (*(vu32 *)PHYS_TO_K1(addr)) + #define PHYS_TO_K1(x) ((u32)(x)|KSEG1) + #define IO_WRITE(addr,data) (*(vu32 *)PHYS_TO_K1(addr)=(u32)(data)) + #define IO_READ(addr) (*(vu32 *)PHYS_TO_K1(addr)) - // PI registers - #define PI_BASE_REG 0x04600000 - #define PI_STATUS_REG (PI_BASE_REG+0x10) - #define PI_STATUS_ERROR 0x04 - #define PI_STATUS_IO_BUSY 0x02 - #define PI_STATUS_DMA_BUSY 0x01 - - #define PI_BSD_DOM1_LAT_REG (PI_BASE_REG+0x14) - #define PI_BSD_DOM1_PWD_REG (PI_BASE_REG+0x18) - #define PI_BSD_DOM1_PGS_REG (PI_BASE_REG+0x1C) - #define PI_BSD_DOM1_RLS_REG (PI_BASE_REG+0x20) - #define PI_BSD_DOM2_LAT_REG (PI_BASE_REG+0x24) - #define PI_BSD_DOM2_PWD_REG (PI_BASE_REG+0x28) - #define PI_BSD_DOM2_PGS_REG (PI_BASE_REG+0x2C) - #define PI_BSD_DOM2_RLS_REG (PI_BASE_REG+0x30) + // Data alignment + #define OS_DCACHE_ROUNDUP_ADDR(x) (void *)(((((u32)(x)+0xf)/0x10)*0x10)) + #define OS_DCACHE_ROUNDUP_SIZE(x) (u32)(((((u32)(x)+0xf)/0x10)*0x10)) #endif -/********************************* - Parallel Interface macros -*********************************/ - -#define N64_PI_ADDRESS 0xA4600000 - -#define N64_PI_RAMADDRESS 0x00 -#define N64_PI_PIADDRESS 0x04 -#define N64_PI_READLENGTH 0x08 -#define N64_PI_WRITELENGTH 0x0C -#define N64_PI_STATUS 0x10 - - /********************************* 64Drive macros *********************************/ -// How many cycles for the 64Drive to wait for data. -// Lowering this might improve performance slightly faster at the expense of USB reading accuracy -#define D64_POLLTIME 2000 +#define D64_COMMAND_TIMEOUT 1000 +#define D64_WRITE_TIMEOUT 1000 -// Cartridge Interface definitions. Obtained from 64Drive's Spec Sheet -#define D64_BASE_ADDRESS 0xB0000000 -#define D64_CIREG_ADDRESS 0x08000000 -#define D64_CIBASE_ADDRESS 0xB8000000 +#define D64_BASE 0x10000000 +#define D64_REGS_BASE 0x18000000 -#define D64_REGISTER_STATUS 0x00000200 -#define D64_REGISTER_COMMAND 0x00000208 -#define D64_REGISTER_LBA 0x00000210 -#define D64_REGISTER_LENGTH 0x00000218 -#define D64_REGISTER_RESULT 0x00000220 +#define D64_REG_STATUS (D64_REGS_BASE + 0x0200) +#define D64_REG_COMMAND (D64_REGS_BASE + 0x0208) -#define D64_REGISTER_MAGIC 0x000002EC -#define D64_REGISTER_VARIANT 0x000002F0 -#define D64_REGISTER_BUTTON 0x000002F8 -#define D64_REGISTER_REVISION 0x000002FC +#define D64_REG_MAGIC (D64_REGS_BASE + 0x02EC) -#define D64_REGISTER_USBCOMSTAT 0x00000400 -#define D64_REGISTER_USBP0R0 0x00000404 -#define D64_REGISTER_USBP1R1 0x00000408 +#define D64_REG_USBCOMSTAT (D64_REGS_BASE + 0x0400) +#define D64_REG_USBP0R0 (D64_REGS_BASE + 0x0404) +#define D64_REG_USBP1R1 (D64_REGS_BASE + 0x0408) -#define D64_ENABLE_ROMWR 0xF0 -#define D64_DISABLE_ROMWR 0xF1 -#define D64_COMMAND_WRITE 0x08 +#define D64_CI_BUSY 0x1000 -// Cartridge Interface return values -#define D64_MAGIC 0x55444556 +#define D64_MAGIC 0x55444556 -#define D64_USB_IDLE 0x00 -#define D64_USB_IDLEUNARMED 0x00 -#define D64_USB_ARMED 0x01 -#define D64_USB_DATA 0x02 -#define D64_USB_ARM 0x0A -#define D64_USB_BUSY 0x0F -#define D64_USB_DISARM 0x0F -#define D64_USB_ARMING 0x0F +#define D64_CI_ENABLE_ROMWR 0xF0 +#define D64_CI_DISABLE_ROMWR 0xF1 -#define D64_CI_IDLE 0x00 -#define D64_CI_BUSY 0x10 -#define D64_CI_WRITE 0x20 +#define D64_CUI_ARM 0x0A +#define D64_CUI_DISARM 0x0F +#define D64_CUI_WRITE 0x08 + +#define D64_CUI_ARM_MASK 0x0F +#define D64_CUI_ARM_IDLE 0x00 +#define D64_CUI_ARM_UNARMED_DATA 0x02 + +#define D64_CUI_WRITE_MASK 0xF0 +#define D64_CUI_WRITE_IDLE 0x00 +#define D64_CUI_WRITE_BUSY 0xF0 /********************************* EverDrive macros *********************************/ +#define ED_TIMEOUT 1000 + #define ED_BASE 0x10000000 #define ED_BASE_ADDRESS 0x1F800000 -#define ED_GET_REGADD(reg) (0xA0000000 | ED_BASE_ADDRESS | (reg)) -#define ED_REG_USBCFG 0x0004 -#define ED_REG_VERSION 0x0014 -#define ED_REG_USBDAT 0x0400 -#define ED_REG_SYSCFG 0x8000 -#define ED_REG_KEY 0x8004 +#define ED_REG_USBCFG (ED_BASE_ADDRESS | 0x0004) +#define ED_REG_VERSION (ED_BASE_ADDRESS | 0x0014) +#define ED_REG_USBDAT (ED_BASE_ADDRESS | 0x0400) +#define ED_REG_SYSCFG (ED_BASE_ADDRESS | 0x8000) +#define ED_REG_KEY (ED_BASE_ADDRESS | 0x8004) -#define ED_USBMODE_RDNOP 0xC400 -#define ED_USBMODE_RD 0xC600 -#define ED_USBMODE_WRNOP 0xC000 -#define ED_USBMODE_WR 0xC200 +#define ED_USBMODE_RDNOP 0xC400 +#define ED_USBMODE_RD 0xC600 +#define ED_USBMODE_WRNOP 0xC000 +#define ED_USBMODE_WR 0xC200 -#define ED_USBSTAT_ACT 0x0200 -#define ED_USBSTAT_RXF 0x0400 -#define ED_USBSTAT_TXE 0x0800 -#define ED_USBSTAT_POWER 0x1000 -#define ED_USBSTAT_BUSY 0x2000 +#define ED_USBSTAT_ACT 0x0200 +#define ED_USBSTAT_RXF 0x0400 +#define ED_USBSTAT_TXE 0x0800 +#define ED_USBSTAT_POWER 0x1000 +#define ED_USBSTAT_BUSY 0x2000 -#define ED_REGKEY 0xAA55 +#define ED_REGKEY 0xAA55 -#define ED25_VERSION 0xED640007 -#define ED3_VERSION 0xED640008 -#define ED7_VERSION 0xED640013 +#define ED25_VERSION 0xED640007 +#define ED3_VERSION 0xED640008 +#define ED7_VERSION 0xED640013 /********************************* - SummerCart64 macros + SC64 macros *********************************/ -#define SC64_SDRAM_BASE (0x10000000) +#define SC64_WRITE_TIMEOUT 1000 -#define SC64_REGS_BASE (0x1FFF0000) -#define SC64_REG_CFG_SR_CMD (SC64_REGS_BASE + 0x00) -#define SC64_REG_CFG_DATA_0 (SC64_REGS_BASE + 0x04) -#define SC64_REG_CFG_DATA_1 (SC64_REGS_BASE + 0x08) -#define SC64_REG_CFG_VERSION (SC64_REGS_BASE + 0x0C) +#define SC64_BASE 0x10000000 +#define SC64_REGS_BASE 0x1FFF0000 -#define SC64_CFG_SR_CMD_ERROR (1 << 28) -#define SC64_CFG_SR_CPU_BUSY (1 << 30) +#define SC64_REG_SR_CMD (SC64_REGS_BASE + 0x00) +#define SC64_REG_DATA_0 (SC64_REGS_BASE + 0x04) +#define SC64_REG_DATA_1 (SC64_REGS_BASE + 0x08) +#define SC64_REG_IDENTIFIER (SC64_REGS_BASE + 0x0C) +#define SC64_REG_KEY (SC64_REGS_BASE + 0x10) -#define SC64_VERSION (0x53437632) +#define SC64_SR_CMD_ERROR (1 << 30) +#define SC64_SR_CMD_BUSY (1 << 31) -#define SC64_CMD_CFG_UPDATE ('C') -#define SC64_CMD_DEBUG_TX_READY ('S') -#define SC64_CMD_DEBUG_TX_DATA ('D') -#define SC64_CMD_DEBUG_RX_READY ('A') -#define SC64_CMD_DEBUG_RX_BUSY ('F') -#define SC64_CMD_DEBUG_RX_DATA ('E') -#define SC64_CMD_DEBUG_RESET ('B') +#define SC64_V2_IDENTIFIER 0x53437632 -#define SC64_CFG_ID_SDRAM_WRITABLE (2) +#define SC64_KEY_RESET 0x00000000 +#define SC64_KEY_UNLOCK_1 0x5F554E4C +#define SC64_KEY_UNLOCK_2 0x4F434B5F -#define SC64_ARGS(args, a0, a1) {args[0] = (a0); args[1] = (a1);} +#define SC64_CMD_CONFIG_SET 'C' +#define SC64_CMD_USB_WRITE_STATUS 'U' +#define SC64_CMD_USB_WRITE 'M' +#define SC64_CMD_USB_READ_STATUS 'u' +#define SC64_CMD_USB_READ 'm' + +#define SC64_CFG_ROM_WRITE_ENABLE 1 + +#define SC64_USB_WRITE_STATUS_BUSY (1 << 31) +#define SC64_USB_READ_STATUS_BUSY (1 << 31) /********************************* @@ -232,19 +212,19 @@ https://github.com/buu342/N64-UNFLoader Function Prototypes *********************************/ -static void usb_findcart(); +static void usb_findcart(void); + static void usb_64drive_write(int datatype, const void* data, int size); -static u32 usb_64drive_poll(); -static void usb_64drive_read(); -static void usb_everdrive_readreg(u32 reg, u32* result); +static u32 usb_64drive_poll(void); +static void usb_64drive_read(void); + static void usb_everdrive_write(int datatype, const void* data, int size); -static u32 usb_everdrive_poll(); -static void usb_everdrive_read(); -static void usb_everdrive_writereg(u64 reg, u32 value); +static u32 usb_everdrive_poll(void); +static void usb_everdrive_read(void); + static void usb_sc64_write(int datatype, const void* data, int size); -static u32 usb_sc64_poll(); -static void usb_sc64_read(); -static u32 usb_sc64_perform_cmd(u8 cmd, u32 *args); +static u32 usb_sc64_poll(void); +static void usb_sc64_read(void); /********************************* @@ -258,14 +238,16 @@ void (*funcPointer_read)(); // USB globals static s8 usb_cart = CART_NONE; -static u8 __attribute__((aligned(16))) usb_buffer[BUFFER_SIZE]; -int usb_datatype = 0; -int usb_datasize = 0; -int usb_dataleft = 0; -int usb_readblock = -1; +static u8 usb_buffer_align[BUFFER_SIZE+16]; // IDO doesn't support GCC's __attribute__((aligned(x))), so this is a workaround +static u8* usb_buffer; +static char usb_didtimeout = FALSE; +static int usb_datatype = 0; +static int usb_datasize = 0; +static int usb_dataleft = 0; +static int usb_readblock = -1; #ifndef LIBDRAGON -// Message globals + // Message globals #if !USE_OSRAW OSMesg dmaMessageBuf; OSIoMesg dmaIOMessageBuf; @@ -285,6 +267,154 @@ int usb_readblock = -1; #endif +/********************************* + I/O Wrapper Functions +*********************************/ + +/*============================== + usb_io_read + Reads a 32-bit value from a + given address using the PI. + @param The address to read from + @return The 4 byte value that was read +==============================*/ + +static inline u32 usb_io_read(u32 pi_address) +{ + #ifndef LIBDRAGON + u32 value; + #if USE_OSRAW + osPiRawReadIo(pi_address, &value); + #else + osPiReadIo(pi_address, &value); + #endif + return value; + #else + return io_read(pi_address); + #endif +} + + +/*============================== + usb_io_write + Writes a 32-bit value to a + given address using the PI. + @param The address to write to + @param The 4 byte value to write +==============================*/ + +static inline void usb_io_write(u32 pi_address, u32 value) +{ + #ifndef LIBDRAGON + #if USE_OSRAW + osPiRawWriteIo(pi_address, value); + #else + osPiWriteIo(pi_address, value); + #endif + #else + io_write(pi_address, value); + #endif +} + + +/*============================== + usb_dma_read + Reads arbitrarily sized data from a + given address using DMA. + @param The buffer to read into + @param The address to read from + @param The size of the data to read +==============================*/ + +static inline void usb_dma_read(void *ram_address, u32 pi_address, size_t size) +{ + #ifndef LIBDRAGON + osWritebackDCache(ram_address, size); + osInvalDCache(ram_address, size); + #if USE_OSRAW + osPiRawStartDma(OS_READ, pi_address, ram_address, size); + #else + osPiStartDma(&dmaIOMessageBuf, OS_MESG_PRI_NORMAL, OS_READ, pi_address, ram_address, size, &dmaMessageQ); + osRecvMesg(&dmaMessageQ, NULL, OS_MESG_BLOCK); + #endif + #else + data_cache_hit_writeback_invalidate(ram_address, size); + dma_read(ram_address, pi_address, size); + #endif +} + + +/*============================== + usb_dma_write + writes arbitrarily sized data to a + given address using DMA. + @param The buffer to read from + @param The address to write to + @param The size of the data to write +==============================*/ + +static inline void usb_dma_write(void *ram_address, u32 pi_address, size_t size) +{ + #ifndef LIBDRAGON + osWritebackDCache(ram_address, size); + #if USE_OSRAW + osPiRawStartDma(OS_WRITE, pi_address, ram_address, size); + #else + osPiStartDma(&dmaIOMessageBuf, OS_MESG_PRI_NORMAL, OS_WRITE, pi_address, ram_address, size, &dmaMessageQ); + osRecvMesg(&dmaMessageQ, NULL, OS_MESG_BLOCK); + #endif + #else + data_cache_hit_writeback(ram_address, size); + dma_write(ram_address, pi_address, size); + #endif +} + + +/********************************* + Timeout helpers +*********************************/ + +/*============================== + usb_timeout_start + Returns current value of COUNT coprocessor 0 register + @return C0_COUNT value +==============================*/ + +static u32 usb_timeout_start(void) +{ +#ifndef LIBDRAGON + return osGetCount(); +#else + return get_ticks(); +#endif +} + + +/*============================== + usb_timeout_check + Checks if timeout occurred + @param Starting value obtained from usb_timeout_start + @param Timeout duration specified in milliseconds + @return TRUE if timeout occurred, otherwise FALSE +==============================*/ + +static char usb_timeout_check(u32 start_ticks, u32 duration) +{ +#ifndef LIBDRAGON + u64 current_ticks = (u64)osGetCount(); + u64 timeout_ticks = OS_USEC_TO_CYCLES((u64)duration * 1000); +#else + u64 current_ticks = (u64)get_ticks(); + u64 timeout_ticks = (u64)TICKS_FROM_MS(duration); +#endif + if (current_ticks < start_ticks) + current_ticks += 0x100000000ULL; + if (current_ticks >= (start_ticks + timeout_ticks)) + return TRUE; + return FALSE; +} + + /********************************* USB functions *********************************/ @@ -295,9 +425,10 @@ int usb_readblock = -1; @returns 1 if the USB initialization was successful, 0 if not ==============================*/ -char usb_initialize() +char usb_initialize(void) { // Initialize the debug related globals + usb_buffer = (u8*)OS_DCACHE_ROUNDUP_ADDR(usb_buffer_align); memset(usb_buffer, 0, BUFFER_SIZE); #ifndef LIBDRAGON @@ -331,75 +462,84 @@ char usb_initialize() default: return 0; } + + // Send a heartbeat + usb_sendheartbeat(); return 1; } /*============================== usb_findcart - Checks if the game is running on a 64Drive, EverDrive or a SummerCart64. + Checks if the game is running on a 64Drive, EverDrive or a SC64. ==============================*/ -static void usb_findcart() +static void usb_findcart(void) { - u32 buff __attribute__((aligned(8))); + u32 buff; + + // Before we do anything, check that we are using an emulator + #if CHECK_EMULATOR + // Check the RDP clock register. + // Always zero on emulators + if (IO_READ(0xA4100010) == 0) // DPC_CLOCK_REG in Libultra + return; + + // Fallback, harder emulator check. + // The VI has an interesting quirk where its values are mirrored every 0x40 bytes + // It's unlikely that emulators handle this, so we'll write to the VI_TEST_ADDR register and readback 0x40 bytes from its address + // If they don't match, we probably have an emulator + buff = (*(u32*)0xA4400038); + (*(u32*)0xA4400038) = 0x6ABCDEF9; + if ((*(u32*)0xA4400038) != (*(u32*)0xA4400078)) + { + (*(u32*)0xA4400038) = buff; + return; + } + (*(u32*)0xA4400038) = buff; + #endif // Read the cartridge and check if we have a 64Drive. - #ifdef LIBDRAGON - buff = io_read(D64_CIBASE_ADDRESS + D64_REGISTER_MAGIC); - #else - #if USE_OSRAW - osPiRawReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_MAGIC, &buff); - #else - osPiReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_MAGIC, &buff); - #endif - #endif - if (buff == D64_MAGIC) + if (usb_io_read(D64_REG_MAGIC) == D64_MAGIC) { usb_cart = CART_64DRIVE; return; } - // Read the cartridge and check if we have a SummerCart64. - #ifdef LIBDRAGON - buff = io_read(SC64_REG_CFG_VERSION); - #else - #if USE_OSRAW - osPiRawReadIo(SC64_REG_CFG_VERSION, &buff); - #else - osPiReadIo(SC64_REG_CFG_VERSION, &buff); - #endif - #endif - if (buff == SC64_VERSION) - { - // Reset USB and flush FIFOs - u32 args[2]; - SC64_ARGS(args, 0, 0); - usb_sc64_perform_cmd(SC64_CMD_DEBUG_RESET, args); - usb_cart = CART_SC64; - return; - } - - // Since we didn't find a 64Drive or SummerCart64, let's assume we have an EverDrive + // Since we didn't find a 64Drive let's assume we have an EverDrive // Write the key to unlock the registers, then read the version register - usb_everdrive_writereg(ED_REG_KEY, ED_REGKEY); - usb_everdrive_readreg(ED_REG_VERSION, &buff); - + usb_io_write(ED_REG_KEY, ED_REGKEY); + buff = usb_io_read(ED_REG_VERSION); + // EverDrive 2.5 not compatible if (buff == ED25_VERSION) return; - + // Check if we have an EverDrive if (buff == ED7_VERSION || buff == ED3_VERSION) { // Set the USB mode - usb_everdrive_writereg(ED_REG_SYSCFG, 0); - usb_everdrive_writereg(ED_REG_USBCFG, ED_USBMODE_RDNOP); + usb_io_write(ED_REG_SYSCFG, 0); + usb_io_write(ED_REG_USBCFG, ED_USBMODE_RDNOP); // Set the cart to EverDrive usb_cart = CART_EVERDRIVE; return; } + + // Since we didn't find an EverDrive either let's assume we have a SC64 + // Write the key sequence to unlock the registers, then read the identifier register + usb_io_write(SC64_REG_KEY, SC64_KEY_RESET); + usb_io_write(SC64_REG_KEY, SC64_KEY_UNLOCK_1); + usb_io_write(SC64_REG_KEY, SC64_KEY_UNLOCK_2); + + // Check if we have a SC64 + if (usb_io_read(SC64_REG_IDENTIFIER) == SC64_V2_IDENTIFIER) + { + // Set the cart to SC64 + usb_cart = CART_SC64; + return; + } } @@ -409,7 +549,7 @@ static void usb_findcart() @return The CART macro that corresponds to the identified flashcart ==============================*/ -char usb_getcart() +char usb_getcart(void) { return usb_cart; } @@ -446,7 +586,7 @@ void usb_write(int datatype, const void* data, int size) @return The data header, or 0 ==============================*/ -unsigned long usb_poll() +u32 usb_poll(void) { // If no debug cart exists, stop if (usb_cart == CART_NONE) @@ -559,7 +699,7 @@ void usb_rewind(int nbytes) Purges the incoming USB data ==============================*/ -void usb_purge() +void usb_purge(void) { usb_dataleft = 0; usb_datatype = 0; @@ -568,141 +708,205 @@ void usb_purge() } +/*============================== + usb_timedout + Checks if the USB timed out recently + @return 1 if the USB timed out, 0 if not +==============================*/ + +char usb_timedout() +{ + return usb_didtimeout; +} + + +/*============================== + usb_sendheartbeat + Sends a heartbeat packet to the PC + This is done once automatically at initialization, + but can be called manually to ensure that the + host side tool is aware of the current USB protocol + version. +==============================*/ + +void usb_sendheartbeat() +{ + u8 buffer[4]; + + // First two bytes describe the USB library protocol version + buffer[0] = (u8)(((USBPROTOCOL_VERSION)>>8)&0xFF); + buffer[1] = (u8)(((USBPROTOCOL_VERSION))&0xFF); + + // Next two bytes describe the heartbeat packet version + buffer[2] = (u8)(((HEARTBEAT_VERSION)>>8)&0xFF); + buffer[3] = (u8)(((HEARTBEAT_VERSION))&0xFF); + + // Send through USB + usb_write(DATATYPE_HEARTBEAT, buffer, sizeof(buffer)/sizeof(buffer[0])); +} + + /********************************* 64Drive functions *********************************/ /*============================== usb_64drive_wait - Wait until the 64Drive is ready - @return 0 if success or -1 if failure + Wait until the 64Drive CI is ready + @return FALSE if success or TRUE if failure ==============================*/ -static s8 usb_64drive_wait() +#ifndef LIBDRAGON +static char usb_64drive_wait(void) +#else +char usb_64drive_wait(void) +#endif { - u32 ret __attribute__((aligned(8))); - u32 timeout = 0; // I wanted to use osGetTime() but that requires the VI manager + u32 timeout; // Wait until the cartridge interface is ready + timeout = usb_timeout_start(); do { - #ifdef LIBDRAGON - ret = io_read(D64_CIBASE_ADDRESS + D64_REGISTER_STATUS); - #else - #if USE_OSRAW - osPiRawReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_STATUS, &ret); - #else - osPiReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_STATUS, &ret); - #endif - #endif - // Took too long, abort - if((timeout++) > 10000) - return -1; + if (usb_timeout_check(timeout, D64_COMMAND_TIMEOUT)) + { + usb_didtimeout = TRUE; + return TRUE; + } } - while((ret >> 8) & D64_CI_BUSY); - (void) timeout; // Needed to stop unused variable warning + while(usb_io_read(D64_REG_STATUS) & D64_CI_BUSY); // Success - return 0; + usb_didtimeout = FALSE; + return FALSE; } /*============================== - usb_64drive_setwritable - Set the write mode on the 64Drive + usb_64drive_set_writable + Set the CARTROM write mode on the 64Drive @param A boolean with whether to enable or disable ==============================*/ -static void usb_64drive_setwritable(u8 enable) +static void usb_64drive_set_writable(u32 enable) { + // Wait until CI is not busy usb_64drive_wait(); - #ifdef LIBDRAGON - io_write(D64_CIBASE_ADDRESS + D64_REGISTER_COMMAND, enable ? D64_ENABLE_ROMWR : D64_DISABLE_ROMWR); - #else - #if USE_OSRAW - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_COMMAND, enable ? D64_ENABLE_ROMWR : D64_DISABLE_ROMWR); - #else - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_COMMAND, enable ? D64_ENABLE_ROMWR : D64_DISABLE_ROMWR); - #endif - #endif + + // Send enable/disable CARTROM writes command + usb_io_write(D64_REG_COMMAND, enable ? D64_CI_ENABLE_ROMWR : D64_CI_DISABLE_ROMWR); + + // Wait until operation is finished usb_64drive_wait(); } /*============================== - usb_64drive_waitidle - Waits for the 64Drive's USB to be idle + usb_64drive_cui_write + Writes data from buffer in the 64drive through USB + @param Data type + @param Offset in CARTROM memory space + @param Transfer size ==============================*/ -static int usb_64drive_waitidle() +static void usb_64drive_cui_write(u8 datatype, u32 offset, u32 size) { - u32 status __attribute__((aligned(8))); - u32 timeout = 0; + u32 timeout; + + // Start USB write + usb_io_write(D64_REG_USBP0R0, offset >> 1); + usb_io_write(D64_REG_USBP1R1, USBHEADER_CREATE(datatype, ALIGN(size, 4))); // Align size to 32-bits due to bugs in the firmware + usb_io_write(D64_REG_USBCOMSTAT, D64_CUI_WRITE); + + // Spin until the write buffer is free + timeout = usb_timeout_start(); do { - #ifdef LIBDRAGON - status = io_read(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT); - #else - #if USE_OSRAW - osPiRawReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, &status); - #else - osPiReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, &status); - #endif - #endif - status = (status >> 4) & D64_USB_BUSY; - if (timeout++ > 128) - return 0; + // Took too long, abort + if (usb_timeout_check(timeout, D64_WRITE_TIMEOUT)) + { + usb_didtimeout = TRUE; + return; + } } - while(status != D64_USB_IDLE); - return 1; + while((usb_io_read(D64_REG_USBCOMSTAT) & D64_CUI_WRITE_MASK) != D64_CUI_WRITE_IDLE); } /*============================== - usb_64drive_armstatus - Checks if the 64Drive is armed - @return The arming status + usb_64drive_cui_poll + Checks if there is data waiting to be read from USB FIFO + @return TRUE if data is waiting, FALSE if otherwise ==============================*/ -static u32 usb_64drive_armstatus() +static char usb_64drive_cui_poll(void) { - u32 status __attribute__((aligned(8))); - #ifdef LIBDRAGON - status = io_read(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT); - #else - #if USE_OSRAW - osPiRawReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, &status); - #else - osPiReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, &status); - #endif - #endif - return status & 0xf; + // Check if we have data waiting in buffer + if ((usb_io_read(D64_REG_USBCOMSTAT) & D64_CUI_ARM_MASK) == D64_CUI_ARM_UNARMED_DATA) + return TRUE; + return FALSE; } /*============================== - usb_64drive_waitdisarmed - Waits for the 64Drive's USB to be disarmed + usb_64drive_cui_read + Reads data from USB FIFO to buffer in the 64drive + @param Offset in CARTROM memory space + @return USB header (datatype + size) ==============================*/ -static void usb_64drive_waitdisarmed() +static u32 usb_64drive_cui_read(u32 offset) { - u32 status __attribute__((aligned(8))); - do + u32 header; + u32 left; + u32 datatype; + u32 size; + + // Arm USB FIFO with 8 byte sized transfer + usb_io_write(D64_REG_USBP0R0, offset >> 1); + usb_io_write(D64_REG_USBP1R1, 8); + usb_io_write(D64_REG_USBCOMSTAT, D64_CUI_ARM); + + // Wait until data is received + while ((usb_io_read(D64_REG_USBCOMSTAT) & D64_CUI_ARM_MASK) != D64_CUI_ARM_UNARMED_DATA) + ; + + // Get datatype and bytes remaining + header = usb_io_read(D64_REG_USBP0R0); + left = usb_io_read(D64_REG_USBP1R1) & 0x00FFFFFF; + datatype = header & 0xFF000000; + size = header & 0x00FFFFFF; + + // Determine if we need to read more data + if (left > 0) { - #ifdef LIBDRAGON - status = io_read(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT); - #else - #if USE_OSRAW - osPiRawReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, &status); - #else - osPiReadIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, &status); - #endif - #endif - status &= 0x0F; + // Arm USB FIFO with known transfer size + usb_io_write(D64_REG_USBP0R0, (offset + 8) >> 1); + usb_io_write(D64_REG_USBP1R1, left); + usb_io_write(D64_REG_USBCOMSTAT, D64_CUI_ARM); + + // Wait until data is received + while ((usb_io_read(D64_REG_USBCOMSTAT) & D64_CUI_ARM_MASK) != D64_CUI_ARM_UNARMED_DATA) + ; + + // Calculate total transfer length + size += left; } - while (status != D64_USB_IDLEUNARMED); + + // Disarm USB FIFO + usb_io_write(D64_REG_USBCOMSTAT, D64_CUI_DISARM); + + // Wait until USB FIFO is disarmed + while ((usb_io_read(D64_REG_USBCOMSTAT) & D64_CUI_ARM_MASK) != D64_CUI_ARM_IDLE) + ; + + // Due to a 64drive bug, we need to ignore the last 512 bytes of the transfer if it's larger than 512 bytes + if (size > 512) + size -= 512; + + // Return data header (datatype and size) + return (datatype | size); } @@ -717,141 +921,43 @@ static void usb_64drive_waitdisarmed() static void usb_64drive_write(int datatype, const void* data, int size) { - int left = size; - int read = 0; + u32 left = size; + u32 pi_address = D64_BASE + DEBUG_ADDRESS; - // Spin until the write buffer is free and then set the cartridge to write mode - if (!usb_64drive_waitidle()) + // Return if previous transfer timed out + if ((usb_io_read(D64_REG_USBCOMSTAT) & D64_CUI_WRITE_MASK) == D64_CUI_WRITE_BUSY) + { + usb_didtimeout = TRUE; return; - usb_64drive_setwritable(TRUE); + } + + // Set the cartridge to write mode + usb_64drive_set_writable(TRUE); // Write data to SDRAM until we've finished while (left > 0) { - int block = left; - if (block > BUFFER_SIZE) - block = BUFFER_SIZE; + // Calculate transfer size + u32 block = MIN(left, BUFFER_SIZE); - // Copy the data to the global buffer - memcpy(usb_buffer, (void*)((char*)data+read), block); + // Copy data to PI DMA aligned buffer + memcpy(usb_buffer, data, block); - // If the data was not 32-bit aligned, pad the buffer - if (block < BUFFER_SIZE && size%4 != 0) - { - u32 i; - u32 size_new = (size & ~3)+4; - block += size_new-size; - for (i=size; i> 1); - io_write(D64_CIBASE_ADDRESS + D64_REGISTER_USBP1R1, (size & 0xFFFFFF) | (datatype << 24)); - io_write(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_COMMAND_WRITE); - #else - #if USE_OSRAW - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP0R0, (DEBUG_ADDRESS) >> 1); - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP1R1, (size & 0xFFFFFF) | (datatype << 24)); - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_COMMAND_WRITE); - #else - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP0R0, (DEBUG_ADDRESS) >> 1); - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP1R1, (size & 0xFFFFFF) | (datatype << 24)); - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_COMMAND_WRITE); - #endif - #endif - - // Spin until the write buffer is free and then disable write mode - usb_64drive_waitidle(); - usb_64drive_setwritable(FALSE); -} - - -/*============================== - usb_64drive_arm - Arms the 64Drive's USB - @param The ROM offset to arm - @param The size of the data to transfer -==============================*/ - -static void usb_64drive_arm(u32 offset, u32 size) -{ - u32 ret __attribute__((aligned(8))); - ret = usb_64drive_armstatus(); - - if (ret != D64_USB_ARMING && ret != D64_USB_ARMED) - { - usb_64drive_waitidle(); - - // Arm the 64Drive, using the ROM space as a buffer - #ifdef LIBDRAGON - io_write(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_USB_ARM); - io_write(D64_CIBASE_ADDRESS + D64_REGISTER_USBP0R0, (offset >> 1)); - io_write(D64_CIBASE_ADDRESS + D64_REGISTER_USBP1R1, (size & 0xFFFFFF)); - #else - #if USE_OSRAW - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_USB_ARM); - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP0R0, (offset >> 1)); - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP1R1, (size & 0xFFFFFF)); - #else - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_USB_ARM); - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP0R0, (offset >> 1)); - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBP1R1, (size & 0xFFFFFF)); - #endif - #endif - } -} - - -/*============================== - usb_64drive_disarm - Disarms the 64Drive's USB -==============================*/ - -static void usb_64drive_disarm() -{ - // Disarm the USB - #ifdef LIBDRAGON - io_write(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_USB_DISARM); - #else - #if USE_OSRAW - osPiRawWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_USB_DISARM); - #else - osPiWriteIo(D64_CIBASE_ADDRESS + D64_REGISTER_USBCOMSTAT, D64_USB_DISARM); - #endif - #endif - usb_64drive_waitdisarmed(); + usb_64drive_cui_write(datatype, DEBUG_ADDRESS, size); + usb_didtimeout = FALSE; } @@ -862,50 +968,27 @@ static void usb_64drive_disarm() @return The data header, or 0 ==============================*/ -static u32 usb_64drive_poll() +static u32 usb_64drive_poll(void) { - int i; - u32 ret __attribute__((aligned(8))); - - // Arm the USB buffer - usb_64drive_waitidle(); - usb_64drive_setwritable(TRUE); - usb_64drive_arm(DEBUG_ADDRESS, DEBUG_ADDRESS_SIZE); - - // Burn some time to see if any USB data comes in - for (i=0; i 0) { - // Wait for the USB to be ready and then read data - usb_everdrive_usbbusy(); - usb_everdrive_readdata(usb_buffer, ED_GET_REGADD(ED_REG_USBDAT), BUFFER_SIZE); // TODO: Replace with usb_everdrive_readusb? + u32 bytes_do = BUFFER_SIZE; + if (len < BUFFER_SIZE) + bytes_do = len; - // Tell the FPGA we can receive more data - if (len != 0) - usb_everdrive_writereg(ED_REG_USBCFG, ED_USBMODE_RD | BUFFER_SIZE); + // Read a chunk from USB and store it into our temp buffer + usb_everdrive_readusb(usb_buffer, bytes_do); // Copy received block to ROM - usb_everdrive_writedata(usb_buffer, ED_BASE + DEBUG_ADDRESS + offset, BUFFER_SIZE); - offset += BUFFER_SIZE; + usb_dma_write(usb_buffer, ED_BASE + DEBUG_ADDRESS + offset, bytes_do); + offset += bytes_do; + len -= bytes_do; } // Read the CMP Signal - usb_everdrive_usbbusy(); - usb_everdrive_readusb(buff, 16); + if (usb_everdrive_usbbusy()) + return 0; + usb_everdrive_readusb(buff, 4); if (buff[0] != 'C' || buff[1] != 'M' || buff[2] != 'P' || buff[3] != 'H') { // Something went wrong with the data @@ -1283,114 +1238,89 @@ static u32 usb_everdrive_poll() Reads bytes from the EverDrive ROM into the global buffer with the block offset ==============================*/ -static void usb_everdrive_read() +static void usb_everdrive_read(void) { // Set up DMA transfer between RDRAM and the PI - #ifdef LIBDRAGON - data_cache_hit_writeback_invalidate(usb_buffer, BUFFER_SIZE); - while (dma_busy()); - *(vu32*)0xA4600010 = 3; - dma_read(usb_buffer, ED_BASE + DEBUG_ADDRESS + usb_readblock, BUFFER_SIZE); - data_cache_hit_writeback_invalidate(usb_buffer, BUFFER_SIZE); - #else - osWritebackDCacheAll(); - #if USE_OSRAW - osPiRawStartDma(OS_READ, - ED_BASE + DEBUG_ADDRESS + usb_readblock, usb_buffer, - BUFFER_SIZE); - #else - osPiStartDma(&dmaIOMessageBuf, OS_MESG_PRI_NORMAL, OS_READ, - ED_BASE + DEBUG_ADDRESS + usb_readblock, usb_buffer, - BUFFER_SIZE, &dmaMessageQ); - (void)osRecvMesg(&dmaMessageQ, NULL, OS_MESG_BLOCK); - #endif - #endif + usb_dma_read(usb_buffer, ED_BASE + DEBUG_ADDRESS + usb_readblock, BUFFER_SIZE); } /********************************* - SummerCart64 functions + SC64 functions *********************************/ /*============================== - usb_sc64_wait_cpu_busy - Wait until command has been processed - @returns If last command resulted in error + usb_sc64_execute_cmd + Executes specified command in SC64 controller + @param Command ID to execute + @param 2 element array of 32 bit arguments to pass with command, use NULL when argument values are not needed + @param 2 element array of 32 bit values to read command result, use NULL when result values are not needed + @return TRUE if there was error during command execution, otherwise FALSE ==============================*/ -static u32 usb_sc64_wait_cpu_busy(void) +#ifndef LIBDRAGON +static char usb_sc64_execute_cmd(u8 cmd, u32 *args, u32 *result) +#else +char usb_sc64_execute_cmd(u8 cmd, u32 *args, u32 *result) +#endif { u32 sr; + // Write arguments if provided + if (args != NULL) + { + usb_io_write(SC64_REG_DATA_0, args[0]); + usb_io_write(SC64_REG_DATA_1, args[1]); + } + + // Start execution + usb_io_write(SC64_REG_SR_CMD, cmd); + + // Wait for completion do { - #ifdef LIBDRAGON - sr = io_read(SC64_REG_CFG_SR_CMD); - #else - #if USE_OSRAW - osPiRawReadIo(SC64_REG_CFG_SR_CMD, &sr); - #else - osPiReadIo(SC64_REG_CFG_SR_CMD, &sr); - #endif - #endif - } while (sr & SC64_CFG_SR_CPU_BUSY); + sr = usb_io_read(SC64_REG_SR_CMD); + } + while (sr & SC64_SR_CMD_BUSY); - return sr & SC64_CFG_SR_CMD_ERROR; + // Read result if provided + if (result != NULL) + { + result[0] = usb_io_read(SC64_REG_DATA_0); + result[1] = usb_io_read(SC64_REG_DATA_1); + } + + // Return error status + if (sr & SC64_SR_CMD_ERROR) + return TRUE; + return FALSE; } /*============================== - usb_sc64_perform_cmd - Issues command to SC64 and waits for completion - @param Command identifier - @param Pointer to 2 element array of arguments that will be overwritten by command result data - @returns If last command resulted in error + usb_sc64_set_writable + Enable ROM (SDRAM) writes in SC64 + @param A boolean with whether to enable or disable + @return Previous value of setting ==============================*/ -static u32 usb_sc64_perform_cmd(u8 cmd, u32 *args) +static u32 usb_sc64_set_writable(u32 enable) { - u32 error = 0; + u32 args[2]; + u32 result[2]; - error |= usb_sc64_wait_cpu_busy(); + args[0] = SC64_CFG_ROM_WRITE_ENABLE; + args[1] = enable; + if (usb_sc64_execute_cmd(SC64_CMD_CONFIG_SET, args, result)) + return 0; - #ifdef LIBDRAGON - io_write(SC64_REG_CFG_DATA_0, args[0]); - io_write(SC64_REG_CFG_DATA_1, args[1]); - io_write(SC64_REG_CFG_SR_CMD, (u32) cmd); - #else - #if USE_OSRAW - osPiRawWriteIo(SC64_REG_CFG_DATA_0, args[0]); - osPiRawWriteIo(SC64_REG_CFG_DATA_1, args[1]); - osPiRawWriteIo(SC64_REG_CFG_SR_CMD, (u32) cmd); - #else - osPiWriteIo(SC64_REG_CFG_DATA_0, args[0]); - osPiWriteIo(SC64_REG_CFG_DATA_1, args[1]); - osPiWriteIo(SC64_REG_CFG_SR_CMD, (u32) cmd); - #endif - #endif - - error |= usb_sc64_wait_cpu_busy(); - - #ifdef LIBDRAGON - args[0] = io_read(SC64_REG_CFG_DATA_0); - args[1] = io_read(SC64_REG_CFG_DATA_1); - #else - #if USE_OSRAW - osPiRawReadIo(SC64_REG_CFG_DATA_0, &args[0]); - osPiRawReadIo(SC64_REG_CFG_DATA_1, &args[1]); - #else - osPiReadIo(SC64_REG_CFG_DATA_0, &args[0]); - osPiReadIo(SC64_REG_CFG_DATA_1, &args[1]); - #endif - #endif - - return error; + return result[1]; } /*============================== usb_sc64_write - Sends data through USB from the SummerCart64 + Sends data through USB from the SC64 @param The DATATYPE that is being sent @param A buffer with the data to send @param The size of the data being sent @@ -1398,176 +1328,124 @@ static u32 usb_sc64_perform_cmd(u8 cmd, u32 *args) static void usb_sc64_write(int datatype, const void* data, int size) { - u8 dma[4] = {'D', 'M', 'A', '@'}; - u32 header = USBHEADER_CREATE(datatype, size); - u8 cmp[4] = {'C', 'M', 'P', 'H'}; - u8 wrote_cmp = FALSE; - - size_t block_size = MIN(BUFFER_SIZE, DEBUG_ADDRESS_SIZE); - size_t usb_block_max_size = DEBUG_ADDRESS_SIZE; - - u8* data_ptr = (u8*) data; - u32 sdram_address = SC64_SDRAM_BASE + DEBUG_ADDRESS; - - int offset; - int left; - u32 transfer_length; + u32 left = size; + u32 pi_address = SC64_BASE + DEBUG_ADDRESS; + u32 writable_restore; + u32 timeout; u32 args[2]; + u32 result[2]; - // Wait until previous data has been transferred - do + // Return if previous transfer timed out + usb_sc64_execute_cmd(SC64_CMD_USB_WRITE_STATUS, NULL, result); + if (result[0] & SC64_USB_WRITE_STATUS_BUSY) { - usb_sc64_perform_cmd(SC64_CMD_DEBUG_TX_READY, args); - } while (!args[0]); + usb_didtimeout = TRUE; + return; + } - // Enable SDRAM writes - SC64_ARGS(args, SC64_CFG_ID_SDRAM_WRITABLE, TRUE); - usb_sc64_perform_cmd(SC64_CMD_CFG_UPDATE, args); - - // Prepare transfer header - memcpy(usb_buffer, dma, sizeof(dma)); - memcpy(usb_buffer + sizeof(dma), &header, sizeof(header)); - - offset = sizeof(dma) + sizeof(header); - left = size; - transfer_length = 0; + // Enable SDRAM writes and get previous setting + writable_restore = usb_sc64_set_writable(TRUE); while (left > 0) { - // Calculate data copy length - size_t data_length = MIN(MIN(left, block_size - offset), usb_block_max_size - transfer_length); - u32 dma_length; + // Calculate transfer size + u32 block = MIN(left, BUFFER_SIZE); - // Fill buffer - memcpy(usb_buffer + offset, data_ptr, data_length); + // Copy data to PI DMA aligned buffer + memcpy(usb_buffer, data, block); - // Write CMPH at the end of data - if (!wrote_cmp && (left - data_length) <= 0) - { - wrote_cmp = TRUE; - data_ptr = cmp; - offset = MIN(offset + data_length, block_size); - left = sizeof(cmp); - continue; - } + // Copy block of data from RDRAM to SDRAM + usb_dma_write(usb_buffer, pi_address, ALIGN(block, 2)); - // Calculate RDRAM -> PI transfer length - dma_length = ALIGN(offset + data_length, 4); - - // Write data to buffer in SDRAM - #ifdef LIBDRAGON - data_cache_hit_writeback(usb_buffer, dma_length); - dma_write(usb_buffer, sdram_address, dma_length); - #else - osWritebackDCache(usb_buffer, dma_length); - #if USE_OSRAW - osPiRawStartDma(OS_WRITE, sdram_address, usb_buffer, dma_length); - #else - osPiStartDma(&dmaIOMessageBuf, OS_MESG_PRI_NORMAL, OS_WRITE, sdram_address, usb_buffer, dma_length, &dmaMessageQ); - osRecvMesg(&dmaMessageQ, NULL, OS_MESG_BLOCK); - #endif - #endif - - // Update pointers and remaining data tracking - data_ptr += data_length; - sdram_address += dma_length; - offset = 0; - left -= data_length; - transfer_length = sdram_address - (SC64_SDRAM_BASE + DEBUG_ADDRESS); - - // Continue filling SDRAM buffer if total length is lower than maximum transfer length or if there's no more data - if ((transfer_length < usb_block_max_size) && (left > 0)) - { - continue; - } - - // Disable SDRAM writes if there's no more data to write - if (left <= 0) - { - SC64_ARGS(args, SC64_CFG_ID_SDRAM_WRITABLE, FALSE); - usb_sc64_perform_cmd(SC64_CMD_CFG_UPDATE, args); - } - - // Start DMA transfer from SDRAM to USB chip - SC64_ARGS(args, DEBUG_ADDRESS, transfer_length); - usb_sc64_perform_cmd(SC64_CMD_DEBUG_TX_DATA, args); - - // Wait for transfer to complete if there's more data to send - if (left > 0) - { - do - { - usb_sc64_perform_cmd(SC64_CMD_DEBUG_TX_READY, args); - } while (!args[0]); - } - - // Reset SDRAM address and transfer length - sdram_address = SC64_SDRAM_BASE + DEBUG_ADDRESS; - transfer_length = 0; + // Update pointers and variables + data += block; + left -= block; + pi_address += block; } + + // Restore previous SDRAM writable setting + usb_sc64_set_writable(writable_restore); + + // Start sending data from buffer in SDRAM + args[0] = SC64_BASE + DEBUG_ADDRESS; + args[1] = USBHEADER_CREATE(datatype, size); + if (usb_sc64_execute_cmd(SC64_CMD_USB_WRITE, args, NULL)) + { + usb_didtimeout = TRUE; + return; // Return if USB write was unsuccessful + } + + // Wait for transfer to end + timeout = usb_timeout_start(); + do + { + // Took too long, abort + if (usb_timeout_check(timeout, SC64_WRITE_TIMEOUT)) + { + usb_didtimeout = TRUE; + return; + } + usb_sc64_execute_cmd(SC64_CMD_USB_WRITE_STATUS, NULL, result); + } + while (result[0] & SC64_USB_WRITE_STATUS_BUSY); + usb_didtimeout = FALSE; } /*============================== usb_sc64_poll - Returns the header of data being received via USB on the SummerCart64 + Returns the header of data being received via USB on the SC64 The first byte contains the data type, the next 3 the number of bytes left to read @return The data header, or 0 ==============================*/ static u32 usb_sc64_poll(void) { + u8 datatype; + u32 size; u32 args[2]; + u32 result[2]; - // Check if there's any data waiting to be serviced - usb_sc64_perform_cmd(SC64_CMD_DEBUG_RX_READY, args); - if (args[0] == 0 && args[1] == 0) { + // Get read status and extract packet info + usb_sc64_execute_cmd(SC64_CMD_USB_READ_STATUS, NULL, result); + datatype = result[0] & 0xFF; + size = result[1] & 0xFFFFFF; + + // Return 0 if there's no data + if (size == 0) return 0; - } // Fill USB read data variables - usb_datatype = USBHEADER_GETTYPE(args[0]); - usb_dataleft = USBHEADER_GETSIZE(args[0]); + usb_datatype = datatype; + usb_dataleft = size; usb_datasize = usb_dataleft; usb_readblock = -1; - // Load data to debug buffer in SDRAM - SC64_ARGS(args, SC64_SDRAM_BASE + DEBUG_ADDRESS, args[1]); - usb_sc64_perform_cmd(SC64_CMD_DEBUG_RX_DATA, args); + // Start receiving data to buffer in SDRAM + args[0] = SC64_BASE + DEBUG_ADDRESS; + args[1] = size; + if (usb_sc64_execute_cmd(SC64_CMD_USB_READ, args, NULL)) + return 0; // Return 0 if USB read was unsuccessful - // Wait until all data has been transferred + // Wait for completion do { - usb_sc64_perform_cmd(SC64_CMD_DEBUG_RX_BUSY, args); - } while (args[0]); + usb_sc64_execute_cmd(SC64_CMD_USB_READ_STATUS, NULL, result); + } + while (result[0] & SC64_USB_READ_STATUS_BUSY); - return USBHEADER_CREATE(usb_datatype, usb_dataleft); + // Return USB header + return USBHEADER_CREATE(datatype, size); } /*============================== usb_sc64_read - Reads bytes from the SummerCart64 ROM into the global buffer with the block offset + Reads bytes from the SC64 SDRAM into the global buffer with the block offset ==============================*/ static void usb_sc64_read(void) { - // Calculate address in SDRAM - u32 sdram_address = SC64_SDRAM_BASE + DEBUG_ADDRESS + usb_readblock; - // Set up DMA transfer between RDRAM and the PI - #ifdef LIBDRAGON - dma_read(usb_buffer, sdram_address, BUFFER_SIZE); - data_cache_hit_invalidate(usb_buffer, BUFFER_SIZE); - #else - #if USE_OSRAW - osPiRawStartDma(OS_READ, sdram_address, usb_buffer, BUFFER_SIZE); - #else - osPiStartDma(&dmaIOMessageBuf, OS_MESG_PRI_NORMAL, OS_READ, sdram_address, usb_buffer, BUFFER_SIZE, &dmaMessageQ); - osRecvMesg(&dmaMessageQ, NULL, OS_MESG_BLOCK); - #endif - - // Invalidate cache - osInvalDCache(usb_buffer, BUFFER_SIZE); - #endif + usb_dma_read(usb_buffer, SC64_BASE + DEBUG_ADDRESS + usb_readblock, BUFFER_SIZE); } diff --git a/src/usb/usb.h b/src/usb/usb.h index 813b1b28..21557746 100644 --- a/src/usb/usb.h +++ b/src/usb/usb.h @@ -1,43 +1,42 @@ #ifndef UNFL_USB_H #define UNFL_USB_H - + +#include "types.h" + /********************************* DataType macros *********************************/ - + // UNCOMMENT THE #DEFINE IF USING LIBDRAGON - //#define LIBDRAGON + //#define LIBDRAGON // Settings #define USE_OSRAW 0 // Use if you're doing USB operations without the PI Manager (libultra only) #define DEBUG_ADDRESS_SIZE 8*1024*1024 // Max size of USB I/O. The bigger this value, the more ROM you lose! - + #define CHECK_EMULATOR 0 // Stops the USB library from working if it detects an emulator to prevent problems + // Cart definitions #define CART_NONE 0 #define CART_64DRIVE 1 #define CART_EVERDRIVE 2 #define CART_SC64 3 - + // Data types defintions #define DATATYPE_TEXT 0x01 #define DATATYPE_RAWBINARY 0x02 #define DATATYPE_HEADER 0x03 #define DATATYPE_SCREENSHOT 0x04 - - extern int usb_datatype; - extern int usb_datasize; - extern int usb_dataleft; - extern int usb_readblock; + #define DATATYPE_HEARTBEAT 0x05 + - /********************************* Convenience macros *********************************/ - + // Use these to conveniently read the header from usb_poll() #define USBHEADER_GETTYPE(header) ((header & 0xFF000000) >> 24) #define USBHEADER_GETSIZE(header) ((header & 0x00FFFFFF)) - + /********************************* USB Functions @@ -48,19 +47,19 @@ Initializes the USB buffers and pointers @return 1 if the USB initialization was successful, 0 if not ==============================*/ - + extern char usb_initialize(); - - + + /*============================== usb_getcart Returns which flashcart is currently connected @return The CART macro that corresponds to the identified flashcart ==============================*/ - + extern char usb_getcart(); - - + + /*============================== usb_write Writes data to the USB. @@ -69,53 +68,74 @@ @param A buffer with the data to send @param The size of the data being sent ==============================*/ - + extern void usb_write(int datatype, const void* data, int size); - - + + /*============================== usb_poll Returns the header of data being received via USB The first byte contains the data type, the next 3 the number of bytes left to read @return The data header, or 0 ==============================*/ - - extern unsigned long usb_poll(); - - + + extern u32 usb_poll(); + + /*============================== usb_read Reads bytes from USB into the provided buffer @param The buffer to put the read data in @param The number of bytes to read ==============================*/ - + extern void usb_read(void* buffer, int size); - - + + /*============================== usb_skip Skips a USB read by the specified amount of bytes @param The number of bytes to skip ==============================*/ - + extern void usb_skip(int nbytes); - - + + /*============================== usb_rewind Rewinds a USB read by the specified amount of bytes @param The number of bytes to rewind ==============================*/ - + extern void usb_rewind(int nbytes); - - + + /*============================== usb_purge Purges the incoming USB data ==============================*/ - + extern void usb_purge(); -#endif \ No newline at end of file + + /*============================== + usb_timedout + Checks if the USB timed out recently + @return 1 if the USB timed out, 0 if not + ==============================*/ + + extern char usb_timedout(); + + + /*============================== + usb_sendheartbeat + Sends a heartbeat packet to the PC + This is done once automatically at initialization, + but can be called manually to ensure that the + host side tool is aware of the current USB protocol + version. + ==============================*/ + + extern void usb_sendheartbeat(); + +#endif From 38e9b086952eae246a1e9539b6b8cdd415b2af76 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Mon, 6 Mar 2023 23:19:15 -0500 Subject: [PATCH 12/13] Fix builds on Make 4.4 (#588) * Fix builds on Make 4.4 * oops --------- Co-authored-by: someone2639 --- Makefile | 6 ++++-- Makefile.split | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a19bd4e2..0aa457f7 100644 --- a/Makefile +++ b/Makefile @@ -693,9 +693,11 @@ $(BUILD_DIR)/%.ci4.inc.c: %.ci4.png $(BUILD_DIR)/%.elf: $(BUILD_DIR)/%.o $(call print,Linking ELF file:,$<,$@) $(V)$(LD) -e 0 -Ttext=$(SEGMENT_ADDRESS) -Map $@.map -o $@ $< -# Override for leveldata.elf, which otherwise matches the above pattern +# Override for leveldata.elf, which otherwise matches the above pattern. +# Has to be a static pattern rule for make-4.4 and above to trigger the second +# expansion. .SECONDEXPANSION: -$(BUILD_DIR)/levels/%/leveldata.elf: $(BUILD_DIR)/levels/%/leveldata.o $(BUILD_DIR)/bin/$$(TEXTURE_BIN).elf +$(LEVEL_ELF_FILES): $(BUILD_DIR)/levels/%/leveldata.elf: $(BUILD_DIR)/levels/%/leveldata.o $(BUILD_DIR)/bin/$$(TEXTURE_BIN).elf $(call print,Linking ELF file:,$<,$@) $(V)$(LD) -e 0 -Ttext=$(SEGMENT_ADDRESS) -Map $@.map --just-symbols=$(BUILD_DIR)/bin/$(TEXTURE_BIN).elf -o $@ $< diff --git a/Makefile.split b/Makefile.split index 6915f55a..8ea95df2 100644 --- a/Makefile.split +++ b/Makefile.split @@ -39,6 +39,8 @@ ACTOR_GROUPS := \ LEVEL_FILES := $(addsuffix leveldata,$(LEVEL_DIRS)) +LEVEL_ELF_FILES := $(foreach level_dir,$(LEVEL_DIRS),$(BUILD_DIR)/levels/$(level_dir)leveldata.elf) + SEG_FILES := \ $(SEGMENTS:%=$(BUILD_DIR)/bin/%.elf) \ $(ACTOR_GROUPS:%=$(BUILD_DIR)/actors/%.elf) \ From 9717d89fb81efd4d2309a972b839e10a78906b2d Mon Sep 17 00:00:00 2001 From: thecozies Date: Fri, 5 May 2023 11:21:53 -0500 Subject: [PATCH 13/13] v2.0.9 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 923fd4d2..c03bb3d4 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -v2.0.8 +v2.0.9