diff --git a/librecomp/include/librecomp/game.hpp b/librecomp/include/librecomp/game.hpp index 5a65997..5bcfaca 100644 --- a/librecomp/include/librecomp/game.hpp +++ b/librecomp/include/librecomp/game.hpp @@ -41,7 +41,7 @@ namespace recomp { void set_rom_contents(std::vector&& new_rom); void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes); void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr); - void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_); + void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input::callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_); void start_game(const std::u8string& game_id); std::u8string current_game_id(); } diff --git a/librecomp/src/cont.cpp b/librecomp/src/cont.cpp index 51a595d..6e33a39 100644 --- a/librecomp/src/cont.cpp +++ b/librecomp/src/cont.cpp @@ -1,14 +1,7 @@ -#include +#include "ultramodern/ultramodern.hpp" + #include "helpers.hpp" -static ultramodern::input_callbacks_t input_callbacks; - -std::chrono::high_resolution_clock::time_point input_poll_time; - -void update_poll_time() { - input_poll_time = std::chrono::high_resolution_clock::now(); -} - extern "C" void recomp_set_current_frame_poll_id(uint8_t* rdram, recomp_context* ctx) { // TODO reimplement the system for tagging polls with IDs to handle games with multithreaded input polling. } @@ -17,14 +10,6 @@ extern "C" void recomp_measure_latency(uint8_t* rdram, recomp_context* ctx) { ultramodern::measure_input_latency(); } -void ultramodern::measure_input_latency() { - // printf("Delta: %ld micros\n", std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - input_poll_time)); -} - -void set_input_callbacks(const ultramodern::input_callbacks_t& callbacks) { - input_callbacks = callbacks; -} - static int max_controllers = 0; extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) { @@ -47,38 +32,17 @@ extern "C" void osContReset_recomp(uint8_t* rdram, recomp_context* ctx) { } extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx) { - if (input_callbacks.poll_input) { - input_callbacks.poll_input(); - } - update_poll_time(); + PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx); - ultramodern::send_si_message(rdram); + s32 ret = osContStartReadData(PASS_RDRAM mq); + + _return(ctx, ret); } extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pad = _arg<0, PTR(void)>(rdram, ctx); + PTR(OSContPad) data = _arg<0, PTR(OSContPad)>(rdram, ctx); - uint16_t buttons = 0; - float x = 0.0f; - float y = 0.0f; - - if (input_callbacks.get_input) { - input_callbacks.get_input(&buttons, &x, &y); - } - - if (max_controllers > 0) { - // button - MEM_H(0, pad) = buttons; - // stick_x - MEM_B(2, pad) = (int8_t)(127 * x); - // stick_y - MEM_B(3, pad) = (int8_t)(127 * y); - // errno - MEM_B(4, pad) = 0; - } - for (int controller = 1; controller < max_controllers; controller++) { - MEM_B(6 * controller + 4, pad) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4 - } + osContGetReadData(PASS_RDRAM data); } extern "C" void osContStartQuery_recomp(uint8_t * rdram, recomp_context * ctx) { @@ -104,46 +68,36 @@ extern "C" void osContSetCh_recomp(uint8_t* rdram, recomp_context* ctx) { } extern "C" void __osMotorAccess_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx); + PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx); s32 flag = _arg<1, s32>(rdram, ctx); - s32 channel = MEM_W(8, pfs); - // Only respect accesses to controller 0. - if (channel == 0) { - input_callbacks.set_rumble(flag); - } + s32 ret = __osMotorAccess(PASS_RDRAM pfs, flag); - _return(ctx, 0); + _return(ctx, ret); } extern "C" void osMotorInit_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<1, PTR(void)>(rdram, ctx); - s32 channel = _arg<2, s32>(rdram, ctx); - MEM_W(8, pfs) = channel; + PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx); + PTR(OSPfs) pfs = _arg<1, PTR(OSPfs)>(rdram, ctx); + int channel = _arg<2, s32>(rdram, ctx); - _return(ctx, 0); + s32 ret = osMotorInit(PASS_RDRAM mq, pfs, channel); + + _return(ctx, ret); } extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx); - s32 channel = MEM_W(8, pfs); + PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx); - // Only respect accesses to controller 0. - if (channel == 0) { - input_callbacks.set_rumble(true); - } + s32 ret = osMotorStart(PASS_RDRAM pfs); - _return(ctx, 0); + _return(ctx, ret); } extern "C" void osMotorStop_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx); - s32 channel = MEM_W(8, pfs); + PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx); - // Only respect accesses to controller 0. - if (channel == 0) { - input_callbacks.set_rumble(false); - } + s32 ret = osMotorStop(PASS_RDRAM pfs); - _return(ctx, 0); + _return(ctx, ret); } diff --git a/librecomp/src/recomp.cpp b/librecomp/src/recomp.cpp index db80bbf..df52937 100644 --- a/librecomp/src/recomp.cpp +++ b/librecomp/src/recomp.cpp @@ -379,8 +379,6 @@ bool ultramodern::is_game_started() { return game_status.load() != GameStatus::None; } -void set_input_callbacks(const ultramodern::input_callbacks_t& callback); - std::atomic_bool exited = false; void ultramodern::quit() { @@ -392,7 +390,7 @@ void ultramodern::quit() { current_game.reset(); } -void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_, const ultramodern::events::callbacks_t& thread_callbacks_, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) { +void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input::callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_, const ultramodern::events::callbacks_t& thread_callbacks_, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) { recomp::check_all_stored_roms(); recomp::rsp::set_callbacks(rsp_callbacks); @@ -404,8 +402,6 @@ void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::c ultramodern::set_callbacks(ultramodern_rsp_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, thread_callbacks_, error_handling_callbacks_); - set_input_callbacks(input_callbacks); - ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_; ultramodern::gfx_callbacks_t::gfx_data_t gfx_data{}; diff --git a/ultramodern/include/ultramodern/ultra64.h b/ultramodern/include/ultramodern/ultra64.h index a202572..a737a45 100644 --- a/ultramodern/include/ultramodern/ultra64.h +++ b/ultramodern/include/ultramodern/ultra64.h @@ -214,6 +214,28 @@ typedef struct { OSViFieldRegs fldRegs[2]; } OSViMode; +/* + * Structure for file system + */ +typedef struct { + int status; + PTR(OSMesgQueue) queue; + int channel; + u8 id[32]; // TODO: funky endianness here + u8 label[32]; // TODO: funky endianness here + int version; + int dir_size; + int inode_table; /* block location */ + int minode_table; /* mirrioring inode_table */ + int dir_table; /* block location */ + int inode_start_page; /* page # */ + // Padding and reversed members due to endianness + u8 padding[2]; + u8 activebank; + u8 banks; +} OSPfs; + + // Controller typedef struct { @@ -285,6 +307,13 @@ s32 osContSetCh(RDRAM_ARG u8); void osContGetQuery(RDRAM_ARG PTR(OSContStatus)); void osContGetReadData(RDRAM_ARG PTR(OSContPad)); +/* Rumble PAK interface */ + +s32 osMotorInit(RDRAM_ARG PTR(OSMesgQueue), PTR(OSPfs), int); +s32 osMotorStop(RDRAM_ARG PTR(OSPfs)); +s32 osMotorStart(RDRAM_ARG PTR(OSPfs)); +s32 __osMotorAccess(RDRAM_ARG PTR(OSPfs), s32); + #ifdef __cplusplus } // extern "C" #endif diff --git a/ultramodern/include/ultramodern/ultramodern.hpp b/ultramodern/include/ultramodern/ultramodern.hpp index 871abee..3649cd6 100644 --- a/ultramodern/include/ultramodern/ultramodern.hpp +++ b/ultramodern/include/ultramodern/ultramodern.hpp @@ -27,6 +27,7 @@ #include "ultramodern/error_handling.hpp" #include "ultramodern/events.hpp" +#include "ultramodern/input.hpp" #include "ultramodern/rsp.hpp" struct UltraThreadContext { @@ -142,17 +143,6 @@ struct audio_callbacks_t { set_frequency_t* set_frequency; }; -// TODO: These functions are currently called by librecomp, but will get called by ultramodern in the future -// Input -struct input_callbacks_t { - using poll_input_t = void(void); - using get_input_t = void(uint16_t*, float*, float*); - using set_rumble_t = void(bool); - poll_input_t* poll_input; - get_input_t* get_input; - set_rumble_t* set_rumble; -}; - // TODO: Most of the members of this struct are not used by ultramodern. Should we move them to librecomp instead? struct gfx_callbacks_t { using gfx_data_t = void*; @@ -178,7 +168,7 @@ void set_audio_callbacks(const audio_callbacks_t& callbacks); * * It must be called only once and it must be called before `ultramodern::preinit`. */ -void set_callbacks(const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& events_callbacks, const error_handling::callbacks_t& error_handling_callbacks); +void set_callbacks(const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input::callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& events_callbacks, const error_handling::callbacks_t& error_handling_callbacks); } // namespace ultramodern #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/ultramodern/src/cont.cpp b/ultramodern/src/cont.cpp index fe31c43..7c18a7c 100644 --- a/ultramodern/src/cont.cpp +++ b/ultramodern/src/cont.cpp @@ -10,10 +10,24 @@ void ultramodern::input::set_callbacks(const callbacks_t& callbacks) { input_callbacks = callbacks; } +static std::chrono::high_resolution_clock::time_point input_poll_time; + +static void update_poll_time() { + input_poll_time = std::chrono::high_resolution_clock::now(); +} + +void ultramodern::measure_input_latency() { +#if 0 + printf("Delta: %ld micros\n", std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - input_poll_time)); +#endif +} + #define MAXCONTROLLERS 4 static int max_controllers = 0; +/* Plain controller */ + static void __osContGetInitData(u8* pattern, OSContStatus *data) { // Set bit 0 to indicate that controller 0 is present *pattern = 0x01; @@ -52,7 +66,14 @@ extern "C" s32 osContStartQuery(RDRAM_ARG PTR(OSMesgQueue) mq) { } extern "C" s32 osContStartReadData(RDRAM_ARG PTR(OSMesgQueue) mq) { - assert(false); + if (input_callbacks.poll_input != nullptr) { + input_callbacks.poll_input(); + } + update_poll_time(); + + ultramodern::send_si_message(rdram); + + return 0; } extern "C" s32 osContSetCh(RDRAM_ARG u8 ch) { @@ -62,12 +83,61 @@ extern "C" s32 osContSetCh(RDRAM_ARG u8 ch) { } extern "C" void osContGetQuery(RDRAM_ARG PTR(OSContStatus) data_) { - u8 pattern; OSContStatus *data = TO_PTR(OSContStatus, data_); + u8 pattern; __osContGetInitData(&pattern, data); } -extern "C" void osContGetReadData(RDRAM_ARG PTR(OSContPad) data) { - assert(false); +extern "C" void osContGetReadData(RDRAM_ARG PTR(OSContPad) data_) { + OSContPad *data = TO_PTR(OSContPad, data_); + uint16_t buttons = 0; + float x = 0.0f; + float y = 0.0f; + + if (input_callbacks.get_input != nullptr) { + input_callbacks.get_input(&buttons, &x, &y); + } + + if (max_controllers > 0) { + // button + data[0].button = buttons; + data[0].stick_x = (int8_t)(127 * x); + data[0].stick_y = (int8_t)(127 * y); + data[0].err_no = 0; + } + for (int controller = 1; controller < max_controllers; controller++) { + data[controller].err_no = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4 + } +} + +/* Rumble */ + +s32 osMotorInit(RDRAM_ARG PTR(OSMesgQueue) mq, PTR(OSPfs) pfs_, int channel) { + OSPfs *pfs = TO_PTR(OSPfs, pfs_); + + pfs->channel = channel; + + return 0; +} + +s32 osMotorStop(RDRAM_ARG PTR(OSPfs) pfs) { + return __osMotorAccess(PASS_RDRAM pfs, false); +} + +s32 osMotorStart(RDRAM_ARG PTR(OSPfs) pfs) { + return __osMotorAccess(PASS_RDRAM pfs, true); +} + +s32 __osMotorAccess(RDRAM_ARG PTR(OSPfs) pfs_, s32 flag) { + OSPfs *pfs = TO_PTR(OSPfs, pfs_); + + // Only respect accesses to controller 0. + if (pfs->channel == 0) { + if (input_callbacks.set_rumble != nullptr) { + input_callbacks.set_rumble(flag); + } + } + + return 0; } diff --git a/ultramodern/src/ultrainit.cpp b/ultramodern/src/ultrainit.cpp index 4fca62a..1517b77 100644 --- a/ultramodern/src/ultrainit.cpp +++ b/ultramodern/src/ultrainit.cpp @@ -4,14 +4,14 @@ void ultramodern::set_callbacks( const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, - const input_callbacks_t& input_callbacks, + const input::callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& thread_callbacks, const error_handling::callbacks_t& error_handling_callbacks ) { ultramodern::rsp::set_callbacks(rsp_callbacks); ultramodern::set_audio_callbacks(audio_callbacks); - (void)input_callbacks; // nothing yet + ultramodern::input::set_callbacks(input_callbacks); (void)gfx_callbacks; // nothing yet ultramodern::events::set_callbacks(thread_callbacks); ultramodern::error_handling::set_callbacks(error_handling_callbacks);