diff --git a/Source/Core/Core/HW/DVD/AMMediaboard.cpp b/Source/Core/Core/HW/DVD/AMMediaboard.cpp index 8533def250..0c2260628c 100644 --- a/Source/Core/Core/HW/DVD/AMMediaboard.cpp +++ b/Source/Core/Core/HW/DVD/AMMediaboard.cpp @@ -152,6 +152,10 @@ static u8 s_network_buffer[512 * 1024]; static u8 s_allnet_buffer[4096]; static u8 s_allnet_settings[0x8500]; +// Fake loading the game to have a chance to enter test mode +static u32 s_board_status = LoadingGameProgram; +static u32 s_load_progress = 80; + static constexpr std::size_t MAX_IPV4_STRING_LENGTH = 15; constexpr char s_allnet_reply[] = { @@ -441,6 +445,9 @@ void Init() std::ranges::fill(s_allnet_buffer, 0); std::ranges::fill(s_allnet_settings, 0); + s_board_status = LoadingGameProgram; + s_load_progress = 80; + s_firmware_map = false; s_test_menu = false; @@ -1746,19 +1753,15 @@ u32 ExecuteCommand(std::array& dicmd_buf, u32* diimm_buf, u32 address, u break; case AMMBCommand::GetMediaBoardStatus: { - // Fake loading the game to have a chance to enter test mode - static u32 status = LoadingGameProgram; - static u32 progress = 80; - - s_media_buffer_32[1] = status; - s_media_buffer_32[2] = progress; - if (progress < 100) + s_media_buffer_32[1] = s_board_status; + s_media_buffer_32[2] = s_load_progress; + if (s_load_progress < 100) { - progress++; + s_load_progress++; } else { - status = LoadedGameProgram; + s_board_status = LoadedGameProgram; } } break; @@ -1974,6 +1977,18 @@ bool GetTestMenu() return s_test_menu; } +static void CloseAllSockets() +{ + for (u32 i = FIRST_VALID_FD; i < std::size(s_sockets); ++i) + { + if (s_sockets[i] != SOCKET_ERROR) + { + closesocket(s_sockets[i]); + s_sockets[i] = SOCKET_ERROR; + } + } +} + void Shutdown() { s_netcfg.Close(); @@ -1983,12 +1998,63 @@ void Shutdown() s_dimm.Close(); s_dimm_disc.clear(); - // Close all sockets - for (u32 i = FIRST_VALID_FD; i < std::size(s_sockets); ++i) + CloseAllSockets(); +} + +void DoState(PointerWrap& p) +{ + p.Do(s_firmware_map); + p.Do(s_test_menu); + p.Do(s_timeouts); + p.Do(s_last_error); + p.Do(s_gcam_key_a); + p.Do(s_gcam_key_b); + p.Do(s_gcam_key_c); + p.Do(s_firmware); + p.Do(s_media_buffer_32); + p.Do(s_network_command_buffer); + p.Do(s_network_buffer); + p.Do(s_allnet_buffer); + p.Do(s_allnet_settings); + + p.Do(s_board_status); + p.Do(s_load_progress); + + // TODO: Handle the files better. + // Data corruption is probably currently possible. + + // s_netcfg + // s_netctrl + // s_extra + // s_backup + // s_dimm + + // TODO: Handle sockets better. + // For now, we just recreate a TCP socket for any socket that existed. + // We should probably re-bind sockets and handle UDP sockets. + + GuestFdSet created_sockets{}; + if (p.IsWriteMode() || p.IsVerifyMode()) { - if (s_sockets[i] != SOCKET_ERROR) + for (u32 i = FIRST_VALID_FD; i < std::size(s_sockets); ++i) { - closesocket(s_sockets[i]); + if (s_sockets[i] != SOCKET_ERROR) + created_sockets.SetFd(GuestSocket(i)); + } + } + + p.Do(created_sockets); + + if (p.IsReadMode()) + { + CloseAllSockets(); + + for (u32 i = FIRST_VALID_FD; i < std::size(s_sockets); ++i) + { + if (!created_sockets.IsFdSet(GuestSocket(i))) + continue; + + s_sockets[i] = socket(AF_INET, SOCK_STREAM, 0); } } } diff --git a/Source/Core/Core/HW/DVD/AMMediaboard.h b/Source/Core/Core/HW/DVD/AMMediaboard.h index cc0bcf9b89..f5d19662ea 100644 --- a/Source/Core/Core/HW/DVD/AMMediaboard.h +++ b/Source/Core/Core/HW/DVD/AMMediaboard.h @@ -8,6 +8,7 @@ #include #include +#include "Common/ChunkFile.h" #include "Common/CommonTypes.h" enum GameType @@ -236,6 +237,7 @@ u32 GetGameType(); u32 GetMediaType(); bool GetTestMenu(); void Shutdown(); +void DoState(PointerWrap& p); std::optional> ParseIPOverride(std::string_view str); diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index 0801b8d26a..33b0efc548 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -124,6 +124,12 @@ void DVDInterface::DoState(PointerWrap& p) m_system.GetDVDThread().DoState(p); m_adpcm_decoder.DoState(p); + + if (m_system.IsTriforce()) + { + AMMediaboard::DoState(p); + p.DoMarker("AMMediaboard"); + } } size_t DVDInterface::ProcessDTKSamples(s16* target_samples, size_t target_block_count, diff --git a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp index 060ff44773..6841d81702 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp +++ b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp @@ -228,9 +228,6 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) std::array data_out{}; u32 data_offset = 0; - static u32 dip_switch_1 = 0xFE; - static u32 dip_switch_0 = 0xFF; - data_out[data_offset++] = 1; data_out[data_offset++] = 1; @@ -304,18 +301,18 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) if (AMMediaboard::GetGameType() == FZeroAX || AMMediaboard::GetGameType() == FZeroAXMonster) { - dip_switch_0 &= ~0x20; + m_dip_switch_0 &= ~0x20; } // Disable camera in MKGP1/2 if (AMMediaboard::GetGameType() == MarioKartGP || AMMediaboard::GetGameType() == MarioKartGP2) { - dip_switch_0 &= ~0x10; + m_dip_switch_0 &= ~0x10; } - data_out[data_offset++] = dip_switch_0; - data_out[data_offset++] = dip_switch_1; + data_out[data_offset++] = m_dip_switch_0; + data_out[data_offset++] = m_dip_switch_1; break; } case GCAMCommand::SerialNumber: @@ -1656,8 +1653,6 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) JVSIOMessage message; - static int delay = 0; - const u8* const frame = &data_in[0]; const u8 nr_bytes = frame[3]; // Byte after E0 xx u32 frame_len = nr_bytes + 3; // Header(2) + length byte + payload + checksum @@ -1694,8 +1689,8 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) " - jvs_io(begin={}, current={}, end={}, n={})\n" " - delay={}, node={}\n" " - frame(begin={}, len={})", - fmt::ptr(jvs_begin), fmt::ptr(jvs_io), fmt::ptr(jvs_end), n, delay, node, - fmt::ptr(frame), frame_len); + fmt::ptr(jvs_begin), fmt::ptr(jvs_io), fmt::ptr(jvs_end), n, m_delay, + node, fmt::ptr(frame), frame_len); jvs_io = jvs_end; return false; }; @@ -2355,7 +2350,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) INFO_LOG_FMT(SERIALINTERFACE_JVSIO, "JVS-IO: Command 0x32, GPO: delay=0x{:02x}, rx_reply=0x{:02x}," " bytes={}, buffer:\n{}", - delay, m_rx_reply, bytes, HexDump(jvs_io, bytes)); + m_delay, m_rx_reply, bytes, HexDump(jvs_io, bytes)); if (bytes < 3) { @@ -2370,8 +2365,8 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) switch (seat_state) { case 0x70: - delay++; - if ((delay % 10) == 0) + m_delay++; + if ((m_delay % 10) == 0) { m_rx_reply = 0xFB; } @@ -2429,13 +2424,13 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) if (*jvs_io++ == 0xD9) { NOTICE_LOG_FMT(SERIALINTERFACE_JVSIO, "JVS-IO: Command 0xF0, Reset"); - delay = 0; + m_delay = 0; m_wheel_init = 0; m_ic_card_state = 0x20; } message.AddData(StatusOkay); - dip_switch_1 |= 1; + m_dip_switch_1 |= 1; break; case JVSIOCommand::SetAddress: if (!validate_jvs_io(1, "SetAddress")) @@ -2444,7 +2439,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) NOTICE_LOG_FMT(SERIALINTERFACE_JVSIO, "JVS-IO: Command 0xF1, SetAddress: node={}", node); message.AddData(node == 1); - dip_switch_1 &= ~1u; + m_dip_switch_1 &= ~1u; break; default: ERROR_LOG_FMT(SERIALINTERFACE_JVSIO, "JVS-IO: Unhandled: node={}, command={:02x}", @@ -2739,4 +2734,73 @@ GCPadStatus CSIDevice_AMBaseboard::GetPadStatus() return pad_status; } +void CSIDevice_AMBaseboard::DoState(PointerWrap& p) +{ + p.Do(m_origin); + p.Do(m_mode); + p.Do(m_timer_button_combo_start); + p.Do(m_last_button_combo); + + p.Do(m_last); + p.Do(m_lastptr); + + p.Do(m_coin); + p.Do(m_coin_pressed); + + p.Do(m_ic_card_data); + + // Setup IC-card + p.Do(m_ic_card_state); + p.Do(m_ic_card_status); + p.Do(m_ic_card_session); + + p.Do(m_ic_write_buffer); + p.Do(m_ic_write_offset); + p.Do(m_ic_write_size); + + p.Do(m_card_memory); + p.Do(m_card_read_packet); + p.Do(m_card_buffer); + + // Setup CARD + p.Do(m_card_memory_size); + p.Do(m_card_is_inserted); + + p.Do(m_card_command); + p.Do(m_card_clean); + p.Do(m_card_write_length); + p.Do(m_card_wrote); + p.Do(m_card_read_length); + p.Do(m_card_read); + p.Do(m_card_bit); + p.Do(m_card_shutter); + p.Do(m_card_state_call_count); + p.Do(m_card_offset); + + // Serial + p.Do(m_wheel_init); + + p.Do(m_motor_init); + p.Do(m_motor_reply); + p.Do(m_motor_force_y); + + // F-Zero AX (DX) + p.Do(m_fzdx_seatbelt); + p.Do(m_fzdx_motion_stop); + p.Do(m_fzdx_sensor_right); + p.Do(m_fzdx_sensor_left); + p.Do(m_rx_reply); + + // F-Zero AX (CyCraft) + p.Do(m_fzcc_seatbelt); + p.Do(m_fzcc_sensor); + p.Do(m_fzcc_emergency); + p.Do(m_fzcc_service); + + p.Do(m_dip_switch_1); + p.Do(m_dip_switch_0); + + p.Do(m_delay); +} + } // namespace SerialInterface diff --git a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h index 95b19a86c6..974325c7c2 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h +++ b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h @@ -71,6 +71,8 @@ public: static bool NetPlay_GetInput(int pad_num, GCPadStatus* status); static int NetPlay_InGamePadToLocalPad(int pad_num); + void DoState(PointerWrap&) override; + protected: struct SOrigin { @@ -311,6 +313,11 @@ private: bool m_fzcc_emergency = false; bool m_fzcc_service = false; + u32 m_dip_switch_1 = 0xFE; + u32 m_dip_switch_0 = 0xFF; + + int m_delay = 0; + void ICCardSendReply(ICCommand* iccommand, u8* buffer, u32* length); };