From 81d3462a199dbaa0c95faa203918cd21d1da1277 Mon Sep 17 00:00:00 2001 From: wwylele Date: Sun, 29 May 2016 12:52:29 +0300 Subject: [PATCH 01/77] Switch context on the same thread if necessary --- src/core/hle/kernel/thread.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3f6bec5fa..db2728a7b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -542,8 +542,12 @@ void Reschedule() { HLE::DoneRescheduling(); - // Don't bother switching to the same thread - if (next == cur) + // Don't bother switching to the same thread. + // But if the thread was waiting on objects, we still need to switch it + // to perform PC modification, change state to RUNNING, etc. + // This occurs in the case when an object the thread is waiting on immediately wakes up + // the current thread before Reschedule() is called. + if (next == cur && (next == nullptr || next->waitsynch_waited == false)) return; if (cur && next) { From dc338ccecf0e5a31242b48ca4f9941039bdf9ca6 Mon Sep 17 00:00:00 2001 From: mailwl Date: Sat, 28 May 2016 20:55:34 +0300 Subject: [PATCH 02/77] srv: Update according 3dbrew --- src/core/hle/service/srv.cpp | 156 +++++++++++++++++++++++++++++++---- 1 file changed, 139 insertions(+), 17 deletions(-) diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index aae955bf8..9aebb67b2 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2016 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -15,23 +15,86 @@ namespace SRV { static Kernel::SharedPtr event_handle; -static void Initialize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = 0; // No error +static const char* NotifDesc(u32 notif_id) { + switch (notif_id) { + case 0x100: return "This indicates that all processes must terminate : power - off, reboot, or FIRM - launch."; + case 0x104: return "This indicates that the system is entering sleep mode. (PTM : NotifySleepPreparationComplete needed for this and the following ? )"; + case 0x105: return "This indicates that the system has exited sleep mode."; + case 0x107: return "Unknown.Subscribed to by CECD module."; + case 0x108: return "error at boot ?"; + case 0x109: return "?(Subscribed to by GSP)"; + case 0x10C: return "Unknown."; + //case 0x110 - 0x11F Unknown.See PM launch flags. + case 0x179: return "Unknown"; + case 0x202: return "POWER button pressed"; + case 0x203: return "POWER button held long"; + case 0x204: return "HOME button pressed"; + case 0x205: return "HOME button released"; + case 0x206: return "This is signaled by NWMEXT : ControlWirelessEnabled and when the physical Wi - Fi slider is enabled"; + case 0x207: return "SD card inserted"; + case 0x208: return "Game cartridge inserted"; + case 0x209: return "SD card removed"; + case 0x20A: return "Game cartridge removed"; + case 0x20B: return "Game cartridge inserted or removed"; + case 0x20D: return "? (Subscribed to by GSP)"; + case 0x20E: return "? (Subscribed to by GSP)"; + case 0x213: return "? (Subscribed to by GSP)"; + case 0x214: return "? (Subscribed to by GSP)"; + case 0x302: return "Unknown.Signaled by nwm module."; + case 0x303: return "Unknown.Subscribed to by CECD module."; + case 0x304: return "Unknown.Subscribed to by CECD module"; + } + return "Unknown notification"; } -static void GetProcSemaphore(Service::Interface* self) { +/** + * SRV::RegisterClient service function + * Inputs: + * 0: 0x00010002 + * 1: ProcessId Header (must be 0x20) + * Outputs: + * 1: ResultCode + */ +static void RegisterClient(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called"); +} + +/** + * SRV::EnableNotification service function + * Inputs: + * 0: 0x00020000 + * Outputs: + * 1: ResultCode + * 2: Translation descriptor: 0x20 + * 3: Handle to semaphore signaled on process notification + */ +static void EnableNotification(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(bunnei): Change to a semaphore once these have been implemented event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); event_handle->Clear(); - cmd_buff[1] = 0; // No error + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0x20; cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); + LOG_WARNING(Service_SRV, "(STUBBED) called"); } +/** + * SRV::EnableNotification service function + * Inputs: + * 0: 0x00050100 + * 1-2: 8-byte UTF-8 service name + * 3: Name length + * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) + * Outputs: + * 1: ResultCode + * 3: Service handle + */ static void GetServiceHandle(Service::Interface* self) { ResultCode res = RESULT_SUCCESS; u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -49,16 +112,74 @@ static void GetServiceHandle(Service::Interface* self) { cmd_buff[1] = res.raw; } +/** + * SRV::Subscribe service function + * Inputs: + * 0: 0x00090040 + * 1: Notification ID + * Outputs: + * 1: ResultCode + */ +static void Subscribe(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notif_id = cmd_buff[1]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, desc: %s", notif_id, NotifDesc(notif_id)); +} + +/** + * SRV::Unsubscribe service function + * Inputs: + * 0: 0x000A0040 + * 1: Notification ID + * Outputs: + * 1: ResultCode + */ +static void Unsubscribe(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notif_id = cmd_buff[1]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, desc: %s", notif_id, NotifDesc(notif_id)); +} + +/** + * SRV::PublishToSubscriber service function + * Inputs: + * 0: 0x000C0080 + * 1: Notification ID + * 2: Flags (bit0: only fire if not fired, bit1: report errors) + * Outputs: + * 1: ResultCode + */ +static void PublishToSubscriber(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notif_id = cmd_buff[1]; + u8 flags = cmd_buff[2] & 0xFF; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, flags=%u, desc: %s", notif_id, flags, NotifDesc(notif_id)); +} + const Interface::FunctionInfo FunctionTable[] = { - {0x00010002, Initialize, "Initialize"}, - {0x00020000, GetProcSemaphore, "GetProcSemaphore"}, - {0x00030100, nullptr, "RegisterService"}, - {0x000400C0, nullptr, "UnregisterService"}, - {0x00050100, GetServiceHandle, "GetServiceHandle"}, - {0x000600C2, nullptr, "RegisterHandle"}, - {0x00090040, nullptr, "Subscribe"}, - {0x000B0000, nullptr, "ReceiveNotification"}, - {0x000C0080, nullptr, "PublishToSubscriber"}, + {0x00010002, RegisterClient, "RegisterClient"}, + {0x00020000, EnableNotification, "EnableNotification"}, + {0x00030100, nullptr, "RegisterService"}, + {0x000400C0, nullptr, "UnregisterService"}, + {0x00050100, GetServiceHandle, "GetServiceHandle"}, + {0x000600C2, nullptr, "RegisterPort"}, + {0x000700C0, nullptr, "UnregisterPort"}, + {0x00080100, nullptr, "GetPort"}, + {0x00090040, Subscribe, "Subscribe"}, + {0x000A0040, Unsubscribe, "Unsubscribe"}, + {0x000B0000, nullptr, "ReceiveNotification"}, + {0x000C0080, PublishToSubscriber, "PublishToSubscriber"}, + {0x000D0040, nullptr, "PublishAndGetSubscriber"}, + {0x000E00C0, nullptr, "IsServiceRegistered"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -66,10 +187,11 @@ const Interface::FunctionInfo FunctionTable[] = { Interface::Interface() { Register(FunctionTable); + event_handle = nullptr; } Interface::~Interface() { event_handle = nullptr; } -} // namespace +} // namespace SRV From eb231cb19d13116e126797532fcffc5ae5410be5 Mon Sep 17 00:00:00 2001 From: mailwl Date: Sat, 28 May 2016 21:29:13 +0300 Subject: [PATCH 03/77] remove ugly function --- src/core/hle/service/srv.cpp | 38 +++--------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 9aebb67b2..76bbe3d1a 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -15,38 +15,6 @@ namespace SRV { static Kernel::SharedPtr event_handle; -static const char* NotifDesc(u32 notif_id) { - switch (notif_id) { - case 0x100: return "This indicates that all processes must terminate : power - off, reboot, or FIRM - launch."; - case 0x104: return "This indicates that the system is entering sleep mode. (PTM : NotifySleepPreparationComplete needed for this and the following ? )"; - case 0x105: return "This indicates that the system has exited sleep mode."; - case 0x107: return "Unknown.Subscribed to by CECD module."; - case 0x108: return "error at boot ?"; - case 0x109: return "?(Subscribed to by GSP)"; - case 0x10C: return "Unknown."; - //case 0x110 - 0x11F Unknown.See PM launch flags. - case 0x179: return "Unknown"; - case 0x202: return "POWER button pressed"; - case 0x203: return "POWER button held long"; - case 0x204: return "HOME button pressed"; - case 0x205: return "HOME button released"; - case 0x206: return "This is signaled by NWMEXT : ControlWirelessEnabled and when the physical Wi - Fi slider is enabled"; - case 0x207: return "SD card inserted"; - case 0x208: return "Game cartridge inserted"; - case 0x209: return "SD card removed"; - case 0x20A: return "Game cartridge removed"; - case 0x20B: return "Game cartridge inserted or removed"; - case 0x20D: return "? (Subscribed to by GSP)"; - case 0x20E: return "? (Subscribed to by GSP)"; - case 0x213: return "? (Subscribed to by GSP)"; - case 0x214: return "? (Subscribed to by GSP)"; - case 0x302: return "Unknown.Signaled by nwm module."; - case 0x303: return "Unknown.Subscribed to by CECD module."; - case 0x304: return "Unknown.Subscribed to by CECD module"; - } - return "Unknown notification"; -} - /** * SRV::RegisterClient service function * Inputs: @@ -126,7 +94,7 @@ static void Subscribe(Service::Interface* self) { u32 notif_id = cmd_buff[1]; cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, desc: %s", notif_id, NotifDesc(notif_id)); + LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X", notif_id); } /** @@ -143,7 +111,7 @@ static void Unsubscribe(Service::Interface* self) { u32 notif_id = cmd_buff[1]; cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, desc: %s", notif_id, NotifDesc(notif_id)); + LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X", notif_id); } /** @@ -162,7 +130,7 @@ static void PublishToSubscriber(Service::Interface* self) { u8 flags = cmd_buff[2] & 0xFF; cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, flags=%u, desc: %s", notif_id, flags, NotifDesc(notif_id)); + LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, flags=%u", notif_id, flags); } const Interface::FunctionInfo FunctionTable[] = { From eea08f281d96791593f5f9fc59bec6e64fd7fc84 Mon Sep 17 00:00:00 2001 From: mailwl Date: Sun, 29 May 2016 12:00:27 +0300 Subject: [PATCH 04/77] Fix mistakes, add output header codes --- src/core/hle/service/srv.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 76bbe3d1a..2afc04d27 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -21,11 +21,19 @@ static Kernel::SharedPtr event_handle; * 0: 0x00010002 * 1: ProcessId Header (must be 0x20) * Outputs: + * 0: 0x00010040 * 1: ResultCode */ static void RegisterClient(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + if (cmd_buff[1] != 0x20) { + cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); //0x40 + cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, + ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; + return; + } + cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); //0x10040 cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_WARNING(Service_SRV, "(STUBBED) called"); } @@ -35,6 +43,7 @@ static void RegisterClient(Service::Interface* self) { * Inputs: * 0: 0x00020000 * Outputs: + * 0: 0x00020042 * 1: ResultCode * 2: Translation descriptor: 0x20 * 3: Handle to semaphore signaled on process notification @@ -46,14 +55,15 @@ static void EnableNotification(Service::Interface* self) { event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); event_handle->Clear(); + cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0x20; + cmd_buff[2] = IPC::CallingPidDesc(); cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); LOG_WARNING(Service_SRV, "(STUBBED) called"); } /** - * SRV::EnableNotification service function + * SRV::GetServiceHandle service function * Inputs: * 0: 0x00050100 * 1-2: 8-byte UTF-8 service name @@ -86,15 +96,17 @@ static void GetServiceHandle(Service::Interface* self) { * 0: 0x00090040 * 1: Notification ID * Outputs: + * 0: 0x00090040 * 1: ResultCode */ static void Subscribe(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 notif_id = cmd_buff[1]; + u32 notification_id = cmd_buff[1]; + cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X", notif_id); + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); } /** @@ -103,15 +115,17 @@ static void Subscribe(Service::Interface* self) { * 0: 0x000A0040 * 1: Notification ID * Outputs: + * 0: 0x000A0040 * 1: ResultCode */ static void Unsubscribe(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 notif_id = cmd_buff[1]; + u32 notification_id = cmd_buff[1]; + cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X", notif_id); + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); } /** @@ -121,16 +135,18 @@ static void Unsubscribe(Service::Interface* self) { * 1: Notification ID * 2: Flags (bit0: only fire if not fired, bit1: report errors) * Outputs: + * 0: 0x000C0040 * 1: ResultCode */ static void PublishToSubscriber(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 notif_id = cmd_buff[1]; + u32 notification_id = cmd_buff[1]; u8 flags = cmd_buff[2] & 0xFF; + cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notif_id=0x%X, flags=%u", notif_id, flags); + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, flags); } const Interface::FunctionInfo FunctionTable[] = { From e85b22320ab339a3f57f829606cf47eabc8f2b04 Mon Sep 17 00:00:00 2001 From: mailwl Date: Tue, 31 May 2016 10:05:31 +0300 Subject: [PATCH 05/77] Fix parameter name in EnableNotification --- src/core/hle/kernel/session.h | 4 ++++ src/core/hle/service/srv.cpp | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 6ddaf970e..26b086f87 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -32,6 +32,10 @@ constexpr u32 CallingPidDesc() { return 0x20; } +constexpr u32 TransferHandleDesc() { + return 0x20; +} + constexpr u32 StaticBufferDesc(u32 size, unsigned int buffer_id) { return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10); } diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 2afc04d27..8bd36d5ea 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -27,7 +27,7 @@ static Kernel::SharedPtr event_handle; static void RegisterClient(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - if (cmd_buff[1] != 0x20) { + if (cmd_buff[1] != IPC::CallingPidDesc()) { cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); //0x40 cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; @@ -57,7 +57,7 @@ static void EnableNotification(Service::Interface* self) { cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = IPC::CallingPidDesc(); + cmd_buff[2] = IPC::TransferHandleDesc(); cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); LOG_WARNING(Service_SRV, "(STUBBED) called"); } From 7d56e8836980891b25d99275a442df80603f5627 Mon Sep 17 00:00:00 2001 From: wwylele Date: Fri, 3 Jun 2016 22:09:09 +0300 Subject: [PATCH 06/77] Thread: update timeout when rerunning WaitSynch --- src/core/hle/kernel/thread.cpp | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3f6bec5fa..492c821e3 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -181,6 +181,48 @@ static void PriorityBoostStarvedThreads() { } } +/** + * Gets the registers for timeout parameter of the next WaitSynchronization call. + * @param thread a pointer to the thread that is ready to call WaitSynchronization + * @returns a tuple of two register pointers to low and high part of the timeout parameter + */ +static std::tuple GetWaitSynchTimeoutParameterRegister(Thread* thread) { + bool thumb_mode = (thread->context.cpsr & TBIT) != 0; + u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE); + u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF; + + if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { + // svc #0x24 (WaitSynchronization1) + return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]); + } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { + // svc #0x25 (WaitSynchronizationN) + return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]); + } + + UNREACHABLE(); +} + +/** + * Updates the WaitSynchronization timeout paramter according to the difference + * between ticks of the last WaitSynchronization call and the incoming one. + * @param timeout_low a pointer to the register for the low part of the timeout parameter + * @param timeout_high a pointer to the register for the high part of the timeout parameter + * @param last_tick tick of the last WaitSynchronization call + */ +static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) { + s64 timeout = ((s64)*timeout_high << 32) | *timeout_low; + + if (timeout != -1) { + timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds + + if (timeout < 0) + timeout = 0; + + *timeout_low = timeout & 0xFFFFFFFF; + *timeout_high = timeout >> 32; + } +} + /** * Switches the CPU's active thread context to that of the specified thread * @param new_thread The thread to switch to @@ -219,6 +261,13 @@ static void SwitchContext(Thread* new_thread) { // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM new_thread->context.pc -= thumb_mode ? 2 : 4; + + // Get the register for timeout parameter + u32* timeout_low, *timeout_high; + std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); + + // Update the timeout parameter + UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks); } // Clean up the thread's wait_objects, they'll be restored if needed during From 3d9fbffbabbe2125ae6208d2d0049552e9293e49 Mon Sep 17 00:00:00 2001 From: Subv Date: Sun, 22 May 2016 11:22:49 -0500 Subject: [PATCH 07/77] Kernel: Added ClientPort and ServerPort classes. This is part of an ongoing effort to implement support for multiple processes. --- src/core/CMakeLists.txt | 4 +++ src/core/hle/kernel/client_port.cpp | 16 +++++++++++ src/core/hle/kernel/client_port.h | 34 +++++++++++++++++++++++ src/core/hle/kernel/kernel.h | 6 ++-- src/core/hle/kernel/server_port.cpp | 38 +++++++++++++++++++++++++ src/core/hle/kernel/server_port.h | 43 +++++++++++++++++++++++++++++ 6 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/core/hle/kernel/client_port.cpp create mode 100644 src/core/hle/kernel/client_port.h create mode 100644 src/core/hle/kernel/server_port.cpp create mode 100644 src/core/hle/kernel/server_port.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ed80cf0e4..2fde9747c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRCS hle/applets/mii_selector.cpp hle/applets/swkbd.cpp hle/kernel/address_arbiter.cpp + hle/kernel/client_port.cpp hle/kernel/event.cpp hle/kernel/kernel.cpp hle/kernel/memory.cpp @@ -36,6 +37,7 @@ set(SRCS hle/kernel/process.cpp hle/kernel/resource_limit.cpp hle/kernel/semaphore.cpp + hle/kernel/server_port.cpp hle/kernel/session.cpp hle/kernel/shared_memory.cpp hle/kernel/thread.cpp @@ -164,6 +166,7 @@ set(HEADERS hle/applets/mii_selector.h hle/applets/swkbd.h hle/kernel/address_arbiter.h + hle/kernel/client_port.h hle/kernel/event.h hle/kernel/kernel.h hle/kernel/memory.h @@ -171,6 +174,7 @@ set(HEADERS hle/kernel/process.h hle/kernel/resource_limit.h hle/kernel/semaphore.h + hle/kernel/server_port.h hle/kernel/session.h hle/kernel/shared_memory.h hle/kernel/thread.h diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp new file mode 100644 index 000000000..444ce8d45 --- /dev/null +++ b/src/core/hle/kernel/client_port.cpp @@ -0,0 +1,16 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_port.h" + +namespace Kernel { + +ClientPort::ClientPort() {} +ClientPort::~ClientPort() {} + +} // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h new file mode 100644 index 000000000..b3d15cfc5 --- /dev/null +++ b/src/core/hle/kernel/client_port.h @@ -0,0 +1,34 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ClientPort : public Object { +public: + friend class ServerPort; + std::string GetTypeName() const override { return "ClientPort"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ClientPort; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + SharedPtr server_port; ///< ServerPort associated with this client port. + u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have + u32 active_sessions; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) + +protected: + ClientPort(); + ~ClientPort() override; +}; + +} // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4d4276f7a..a53d408d4 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -35,7 +35,7 @@ enum KernelHandle : Handle { enum class HandleType : u32 { Unknown = 0, - Port = 1, + ServerPort = 1, Session = 2, Event = 3, Mutex = 4, @@ -48,6 +48,7 @@ enum class HandleType : u32 { Timer = 11, ResourceLimit = 12, CodeSet = 13, + ClientPort = 14, }; enum { @@ -72,6 +73,7 @@ public: bool IsWaitable() const { switch (GetHandleType()) { case HandleType::Session: + case HandleType::ServerPort: case HandleType::Event: case HandleType::Mutex: case HandleType::Thread: @@ -80,13 +82,13 @@ public: return true; case HandleType::Unknown: - case HandleType::Port: case HandleType::SharedMemory: case HandleType::Redirection: case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: case HandleType::CodeSet: + case HandleType::ClientPort: return false; } } diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp new file mode 100644 index 000000000..ca41265ff --- /dev/null +++ b/src/core/hle/kernel/server_port.cpp @@ -0,0 +1,38 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +ServerPort::ServerPort() {} +ServerPort::~ServerPort() {} + +bool ServerPort::ShouldWait() { + // If there are no pending sessions, we wait until a new one is added. + return pending_sessions.size() == 0; +} + +void ServerPort::Acquire() { + ASSERT_MSG(!ShouldWait(), "object unavailable!"); +} + +std::tuple, SharedPtr> ServerPort::CreatePortPair(u32 max_sessions, std::string name) { + SharedPtr server_port(new ServerPort); + SharedPtr client_port(new ClientPort); + + server_port->name = name + "_Server"; + client_port->name = name + "_Client"; + client_port->server_port = server_port; + client_port->max_sessions = max_sessions; + client_port->active_sessions = 0; + + return std::make_tuple(std::move(server_port), std::move(client_port)); +} + +} // namespace diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h new file mode 100644 index 000000000..e41ef8ce4 --- /dev/null +++ b/src/core/hle/kernel/server_port.h @@ -0,0 +1,43 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ServerPort final : public WaitObject { +public: + /** + * Creates a pair of a ServerPort and an associated ClientPort. + * @param max_sessions Maximum number of sessions to the port + * @param name Optional name of the ports + * @return The created port tuple + */ + static std::tuple, SharedPtr> CreatePortPair(u32 max_sessions, std::string name = "UnknownPort"); + + std::string GetTypeName() const override { return "ServerPort"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ServerPort; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + std::string name; ///< Name of port (optional) + + std::vector> pending_sessions; ///< ServerSessions waiting to be accepted by the port + + bool ShouldWait() override; + void Acquire() override; + +private: + ServerPort(); + ~ServerPort() override; +}; + +} // namespace From c900c092e329d2e78b9663c1c3fe401da7faaea5 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Mon, 23 May 2016 16:03:11 +0200 Subject: [PATCH 08/77] OpenGL: Avoid undefined behaviour for UNIFORM_BLOCK_DATA_SIZE --- src/video_core/renderer_opengl/gl_rasterizer.h | 10 ++++++---- src/video_core/renderer_opengl/gl_shader_gen.cpp | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index bb7f20161..bdc7bd0f2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -316,16 +316,18 @@ private: GLfloat dist_atten_scale; }; - /// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned + /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned + // NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at + // the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. + // Not following that rule will cause problems on some AMD drivers. struct UniformData { - // A vec4 color for each of the six tev stages - GLvec4 const_color[6]; - GLvec4 tev_combiner_buffer_color; GLint alphatest_ref; GLfloat depth_scale; GLfloat depth_offset; alignas(16) GLvec3 lighting_global_ambient; LightSrc light_src[8]; + alignas(16) GLvec4 const_color[6]; // A vec4 color for each of the six tev stages + alignas(16) GLvec4 tev_combiner_buffer_color; }; static_assert(sizeof(UniformData) == 0x390, "The size of the UniformData structure has changed, update the structure in the shader"); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 8332e722d..ea7ab2883 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -552,13 +552,13 @@ struct LightSrc { }; layout (std140) uniform shader_data { - vec4 const_color[NUM_TEV_STAGES]; - vec4 tev_combiner_buffer_color; int alphatest_ref; float depth_scale; float depth_offset; vec3 lighting_global_ambient; LightSrc light_src[NUM_LIGHTS]; + vec4 const_color[NUM_TEV_STAGES]; + vec4 tev_combiner_buffer_color; }; uniform sampler2D tex[3]; From 57855a1701474c65b8dd95d0c312d02fae8fe1a6 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Wed, 11 May 2016 13:39:28 +0200 Subject: [PATCH 09/77] Pica: Add fog state --- src/video_core/command_processor.cpp | 14 ++++++++ src/video_core/pica.h | 53 +++++++++++++++++++++------- src/video_core/pica_state.h | 16 +++++++-- 3 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 19e03adf4..689859049 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -423,6 +423,20 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { break; } + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): + { + g_state.fog.lut[regs.fog_lut_offset % 128].raw = value; + regs.fog_lut_offset.Assign(regs.fog_lut_offset + 1); + break; + } + default: break; } diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 544ea037f..09702d46a 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -401,22 +401,47 @@ struct Regs { TevStageConfig tev_stage3; INSERT_PADDING_WORDS(0x3); + enum class FogMode : u32 { + None = 0, + Fog = 5, + Gas = 7, + }; + union { - // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in - // these masks are set - BitField< 8, 4, u32> update_mask_rgb; - BitField<12, 4, u32> update_mask_a; + BitField<0, 3, FogMode> fog_mode; + BitField<16, 1, u32> fog_flip; - bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { - return (stage_index < 4) && (update_mask_rgb & (1 << stage_index)); - } + union { + // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in + // these masks are set + BitField< 8, 4, u32> update_mask_rgb; + BitField<12, 4, u32> update_mask_a; - bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { - return (stage_index < 4) && (update_mask_a & (1 << stage_index)); - } - } tev_combiner_buffer_input; + bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { + return (stage_index < 4) && (update_mask_rgb & (1 << stage_index)); + } + + bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { + return (stage_index < 4) && (update_mask_a & (1 << stage_index)); + } + } tev_combiner_buffer_input; + }; + + union { + u32 raw; + BitField< 0, 8, u32> r; + BitField< 8, 8, u32> g; + BitField<16, 8, u32> b; + } fog_color; + + INSERT_PADDING_WORDS(0x4); + + BitField<0, 16, u32> fog_lut_offset; + + INSERT_PADDING_WORDS(0x1); + + u32 fog_lut_data[8]; - INSERT_PADDING_WORDS(0xf); TevStageConfig tev_stage4; INSERT_PADDING_WORDS(0x3); TevStageConfig tev_stage5; @@ -1318,6 +1343,10 @@ ASSERT_REG_POSITION(tev_stage1, 0xc8); ASSERT_REG_POSITION(tev_stage2, 0xd0); ASSERT_REG_POSITION(tev_stage3, 0xd8); ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0); +ASSERT_REG_POSITION(fog_mode, 0xe0); +ASSERT_REG_POSITION(fog_color, 0xe1); +ASSERT_REG_POSITION(fog_lut_offset, 0xe6); +ASSERT_REG_POSITION(fog_lut_data, 0xe8); ASSERT_REG_POSITION(tev_stage4, 0xf0); ASSERT_REG_POSITION(tev_stage5, 0xf8); ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd); diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h index 495174c25..01f4285a8 100644 --- a/src/video_core/pica_state.h +++ b/src/video_core/pica_state.h @@ -33,10 +33,10 @@ struct State { u32 raw; // LUT value, encoded as 12-bit fixed point, with 12 fraction bits - BitField< 0, 12, u32> value; + BitField< 0, 12, u32> value; // 0.0.12 fixed point // Used by HW for efficient interpolation, Citra does not use these - BitField<12, 12, u32> difference; + BitField<12, 12, s32> difference; // 1.0.11 fixed point float ToFloat() { return static_cast(value) / 4095.f; @@ -46,6 +46,18 @@ struct State { std::array, 24> luts; } lighting; + struct { + union LutEntry { + // Used for raw access + u32 raw; + + BitField< 0, 13, s32> difference; // 1.1.11 fixed point + BitField<13, 11, u32> value; // 0.0.11 fixed point + }; + + std::array lut; + } fog; + /// Current Pica command list struct { const u32* head_ptr; From ebee2513a9389e6e79baebcd8431e1a3495d58a6 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Wed, 11 May 2016 13:39:56 +0200 Subject: [PATCH 10/77] Rasterizer: Implement fog --- src/video_core/rasterizer.cpp | 73 +++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 65168f05a..a84170094 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -398,6 +398,26 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, float24::FromFloat32(static_cast(w2))); float24 interpolated_w_inverse = float24::FromFloat32(1.0f) / Math::Dot(w_inverse, baricentric_coordinates); + // interpolated_z = z / w + float interpolated_z_over_w = (v0.screenpos[2].ToFloat32() * w0 + + v1.screenpos[2].ToFloat32() * w1 + + v2.screenpos[2].ToFloat32() * w2) / wsum; + + // Not fully accurate. About 3 bits in precision are missing. + // Z-Buffer (z / w * scale + offset) + float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32(); + float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32(); + float depth = interpolated_z_over_w * depth_scale + depth_offset; + + // Potentially switch to W-Buffer + if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { + // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w) + depth *= interpolated_w_inverse.ToFloat32() * wsum; + } + + // Clamp the result + depth = MathUtil::Clamp(depth, 0.0f, 1.0f); + // Perspective correct attribute interpolation: // Attribute values cannot be calculated by simple linear interpolation since // they are not linear in screen space. For example, when interpolating a @@ -833,6 +853,38 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, continue; } + // Apply fog combiner + // Not fully accurate. We'd have to know what data type is used to + // store the depth etc. Using float for now until we know more + // about Pica datatypes + if (regs.fog_mode == Regs::FogMode::Fog) { + const Math::Vec3 fog_color = { + static_cast(regs.fog_color.r.Value()), + static_cast(regs.fog_color.g.Value()), + static_cast(regs.fog_color.b.Value()), + }; + + // Get index into fog LUT + float fog_index; + if (g_state.regs.fog_flip) { + fog_index = (1.0f - depth) * 128.0f; + } else { + fog_index = depth * 128.0f; + } + + // Generate clamped fog factor from LUT for given fog index + float fog_i = MathUtil::Clamp(floorf(fog_index), 0.0f, 127.0f); + float fog_f = fog_index - fog_i; + const auto& fog_lut_entry = g_state.fog.lut[static_cast(fog_i)]; + float fog_factor = (fog_lut_entry.value + fog_lut_entry.difference * fog_f) / 2047.0f; // This is signed fixed point 1.11 + fog_factor = MathUtil::Clamp(fog_factor, 0.0f, 1.0f); + + // Blend the fog + for (unsigned i = 0; i < 3; i++) { + combiner_output[i] = fog_factor * combiner_output[i] + (1.0f - fog_factor) * fog_color[i]; + } + } + u8 old_stencil = 0; auto UpdateStencil = [stencil_test, x, y, &old_stencil](Pica::Regs::StencilAction action) { @@ -887,27 +939,6 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, } } - // interpolated_z = z / w - float interpolated_z_over_w = (v0.screenpos[2].ToFloat32() * w0 + - v1.screenpos[2].ToFloat32() * w1 + - v2.screenpos[2].ToFloat32() * w2) / wsum; - - // Not fully accurate. About 3 bits in precision are missing. - // Z-Buffer (z / w * scale + offset) - float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32(); - float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32(); - float depth = interpolated_z_over_w * depth_scale + depth_offset; - - // Potentially switch to W-Buffer - if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { - - // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w) - depth *= interpolated_w_inverse.ToFloat32() * wsum; - } - - // Clamp the result - depth = MathUtil::Clamp(depth, 0.0f, 1.0f); - // Convert float to integer unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); u32 z = (u32)(depth * ((1 << num_bits) - 1)); From a12571c709c5af840bb89c43344bd982a496f21a Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 21 May 2016 01:04:57 +0200 Subject: [PATCH 11/77] OpenGL: Implement fog --- .../renderer_opengl/gl_rasterizer.cpp | 68 +++++++++++++++++++ .../renderer_opengl/gl_rasterizer.h | 17 ++++- .../renderer_opengl/gl_shader_gen.cpp | 34 ++++++++-- src/video_core/renderer_opengl/gl_state.cpp | 8 +++ src/video_core/renderer_opengl/gl_state.h | 4 ++ 5 files changed, 124 insertions(+), 7 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 931c34a37..328a4f66b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -62,6 +62,8 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { uniform_block_data.lut_dirty[index] = true; } + uniform_block_data.fog_lut_dirty = true; + // Set vertex attributes glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); @@ -102,6 +104,18 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } + // Setup the LUT for the fog + { + fog_lut.Create(); + state.fog_lut.texture_1d = fog_lut.handle; + } + state.Apply(); + + glActiveTexture(GL_TEXTURE9); + glTexImage1D(GL_TEXTURE_1D, 0, GL_R32UI, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // Sync fixed function OpenGL state SyncCullMode(); SyncBlendEnabled(); @@ -215,6 +229,12 @@ void RasterizerOpenGL::DrawTriangles() { } } + // Sync the fog lut + if (uniform_block_data.fog_lut_dirty) { + SyncFogLUT(); + uniform_block_data.fog_lut_dirty = false; + } + // Sync the uniform data if (uniform_block_data.dirty) { glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW); @@ -280,6 +300,21 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { SyncBlendColor(); break; + // Fog state + case PICA_REG_INDEX(fog_color): + SyncFogColor(); + break; + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee): + case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): + uniform_block_data.fog_lut_dirty = true; + break; + // Alpha test case PICA_REG_INDEX(output_merger.alpha_test): SyncAlphaTest(); @@ -329,6 +364,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { break; // TEV stages + // (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input) case PICA_REG_INDEX(tev_stage0.color_source1): case PICA_REG_INDEX(tev_stage0.color_modifier1): case PICA_REG_INDEX(tev_stage0.color_op): @@ -950,9 +986,15 @@ void RasterizerOpenGL::SetShader() { uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]"); if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); } + GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut"); + if (uniform_fog_lut != -1) { glUniform1i(uniform_fog_lut, 9); } + current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); + GLint block_size; + glGetActiveUniformBlockiv(current_shader->shader.handle, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); + ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!"); glUniformBlockBinding(current_shader->shader.handle, block_index, 0); // Update uniforms @@ -974,6 +1016,8 @@ void RasterizerOpenGL::SetShader() { SyncLightDistanceAttenuationBias(light_index); SyncLightDistanceAttenuationScale(light_index); } + + SyncFogColor(); } } @@ -1040,6 +1084,30 @@ void RasterizerOpenGL::SyncBlendColor() { state.blend.color.alpha = blend_color[3]; } +void RasterizerOpenGL::SyncFogColor() { + const auto& regs = Pica::g_state.regs; + uniform_block_data.data.fog_color = { + regs.fog_color.r.Value() / 255.0f, + regs.fog_color.g.Value() / 255.0f, + regs.fog_color.b.Value() / 255.0f + }; + uniform_block_data.dirty = true; +} + +void RasterizerOpenGL::SyncFogLUT() { + std::array new_data; + + std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(), [](const auto& entry) { + return entry.raw; + }); + + if (new_data != fog_lut_data) { + fog_lut_data = new_data; + glActiveTexture(GL_TEXTURE9); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT, fog_lut_data.data()); + } +} + void RasterizerOpenGL::SyncAlphaTest() { const auto& regs = Pica::g_state.regs; if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index bdc7bd0f2..42482df4b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -76,6 +76,9 @@ union PicaShaderConfig { state.tev_stages[i].scales_raw = tev_stage.scales_raw; } + state.fog_mode = regs.fog_mode; + state.fog_flip = regs.fog_flip; + state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() | regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; @@ -168,13 +171,14 @@ union PicaShaderConfig { }; struct State { - Pica::Regs::CompareFunc alpha_test_func; Pica::Regs::TextureConfig::TextureType texture0_type; std::array tev_stages; u8 combiner_buffer_input; Pica::Regs::DepthBuffering depthmap_enable; + Pica::Regs::FogMode fog_mode; + bool fog_flip; struct { struct { @@ -324,13 +328,14 @@ private: GLint alphatest_ref; GLfloat depth_scale; GLfloat depth_offset; + alignas(16) GLvec3 fog_color; alignas(16) GLvec3 lighting_global_ambient; LightSrc light_src[8]; alignas(16) GLvec4 const_color[6]; // A vec4 color for each of the six tev stages alignas(16) GLvec4 tev_combiner_buffer_color; }; - static_assert(sizeof(UniformData) == 0x390, "The size of the UniformData structure has changed, update the structure in the shader"); + static_assert(sizeof(UniformData) == 0x3A0, "The size of the UniformData structure has changed, update the structure in the shader"); static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); /// Sets the OpenGL shader in accordance with the current PICA register state @@ -354,6 +359,10 @@ private: /// Syncs the blend color to match the PICA register void SyncBlendColor(); + /// Syncs the fog states to match the PICA register + void SyncFogColor(); + void SyncFogLUT(); + /// Syncs the alpha test states to match the PICA register void SyncAlphaTest(); @@ -421,6 +430,7 @@ private: struct { UniformData data; bool lut_dirty[6]; + bool fog_lut_dirty; bool dirty; } uniform_block_data = {}; @@ -432,4 +442,7 @@ private: std::array lighting_luts; std::array, 6> lighting_lut_data{}; + + OGLTexture fog_lut; + std::array fog_lut_data{}; }; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index ea7ab2883..3bace7f01 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -555,6 +555,7 @@ layout (std140) uniform shader_data { int alphatest_ref; float depth_scale; float depth_offset; + vec3 fog_color; vec3 lighting_global_ambient; LightSrc light_src[NUM_LIGHTS]; vec4 const_color[NUM_TEV_STAGES]; @@ -563,6 +564,7 @@ layout (std140) uniform shader_data { uniform sampler2D tex[3]; uniform sampler1D lut[6]; +uniform usampler1D fog_lut; // Rotate the vector v by the quaternion q vec3 quaternion_rotate(vec4 q, vec3 v) { @@ -580,6 +582,12 @@ vec4 secondary_fragment_color = vec4(0.0); return out; } + out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; + out += "float depth = z_over_w * depth_scale + depth_offset;\n"; + if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { + out += "depth /= gl_FragCoord.w;\n"; + } + if (state.lighting.enable) WriteLighting(out, config); @@ -596,14 +604,30 @@ vec4 secondary_fragment_color = vec4(0.0); out += ") discard;\n"; } - out += "color = last_tex_env_out;\n"; + // Append fog combiner + if (state.fog_mode == Regs::FogMode::Fog) { + // Get index into fog LUT + if (state.fog_flip) { + out += "float fog_index = (1.0 - depth) * 128.0;\n"; + } else { + out += "float fog_index = depth * 128.0;\n"; + } - out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; - out += "float depth = z_over_w * depth_scale + depth_offset;\n"; - if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { - out += "depth /= gl_FragCoord.w;\n"; + // Generate clamped fog factor from LUT for given fog index + out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n"; + out += "float fog_f = fog_index - fog_i;\n"; + out += "uint fog_lut_entry = texelFetch(fog_lut, int(fog_i), 0).r;\n"; + out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> 19);\n"; // Extract signed difference + out += "float fog_lut_entry_value = float((fog_lut_entry >> 13U) & 0x7FFU);\n"; + out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / 2047.0;\n"; + out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n"; + + // Blend the fog + out += "last_tex_env_out.rgb = mix(fog_color.rgb, last_tex_env_out.rgb, fog_factor);\n"; } + out += "gl_FragDepth = depth;\n"; + out += "color = last_tex_env_out;\n"; out += "}"; diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index fa141fc9a..13ee986b9 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -58,6 +58,8 @@ OpenGLState::OpenGLState() { lut.texture_1d = 0; } + fog_lut.texture_1d = 0; + draw.read_framebuffer = 0; draw.draw_framebuffer = 0; draw.vertex_array = 0; @@ -195,6 +197,12 @@ void OpenGLState::Apply() const { } } + // Fog LUT + if (fog_lut.texture_1d != cur_state.fog_lut.texture_1d) { + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_1D, fog_lut.texture_1d); + } + // Framebuffer if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 228727054..13c71b0a6 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -67,6 +67,10 @@ public: GLuint texture_1d; // GL_TEXTURE_BINDING_1D } lighting_luts[6]; + struct { + GLuint texture_1d; // GL_TEXTURE_BINDING_1D + } fog_lut; + struct { GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING From f9e3824820b92b886dd072f396dee2221daabb20 Mon Sep 17 00:00:00 2001 From: LFsWang Date: Wed, 8 Jun 2016 13:53:41 +0800 Subject: [PATCH 12/77] Fix boot_filename encode on Windows --- src/citra/citra.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index e01216734..128b9a16d 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -17,11 +17,16 @@ #include #endif +#ifdef _WIN32 +#include +#endif + #include "common/logging/log.h" #include "common/logging/backend.h" #include "common/logging/filter.h" #include "common/scm_rev.h" #include "common/scope_exit.h" +#include "common/string_util.h" #include "core/settings.h" #include "core/system.h" @@ -55,6 +60,15 @@ int main(int argc, char **argv) { bool use_gdbstub = Settings::values.use_gdbstub; u32 gdb_port = static_cast(Settings::values.gdbstub_port); char *endarg; +#ifdef _WIN32 + int argc_w; + auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); + + if (argv_w == nullptr) { + LOG_CRITICAL(Frontend, "Failed to get command line arguments"); + return -1; + } +#endif std::string boot_filename; static struct option long_options[] = { @@ -86,11 +100,19 @@ int main(int argc, char **argv) { return 0; } } else { +#ifdef _WIN32 + boot_filename = Common::UTF16ToUTF8(argv_w[optind]); +#else boot_filename = argv[optind]; +#endif optind++; } } +#ifdef _WIN32 + LocalFree(argv_w); +#endif + Log::Filter log_filter(Log::Level::Debug); Log::SetFilter(&log_filter); From 2c482722e79e3994266898650dddc57e393f1112 Mon Sep 17 00:00:00 2001 From: archshift Date: Fri, 10 Jun 2016 18:25:30 -0700 Subject: [PATCH 13/77] arm_dyncom_interpreter.cpp: #include translation info from inc files --- .../arm/dyncom/arm_dyncom_interpreter.cpp | 2650 +---------------- src/core/arm/dyncom/arm_dyncom_trans.inc | 2188 ++++++++++++++ .../arm/dyncom/arm_dyncom_trans_struct.inc | 462 +++ 3 files changed, 2652 insertions(+), 2648 deletions(-) create mode 100644 src/core/arm/dyncom/arm_dyncom_trans.inc create mode 100644 src/core/arm/dyncom/arm_dyncom_trans_struct.inc diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index cfc67287f..b45a6cd64 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -668,462 +668,7 @@ static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst, u virt_addr = addr; } -struct arm_inst { - unsigned int idx; - unsigned int cond; - int br; - char component[0]; -}; - -struct generic_arm_inst { - u32 Ra; - u32 Rm; - u32 Rn; - u32 Rd; - u8 op1; - u8 op2; -}; - -struct adc_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct add_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct orr_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct and_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct eor_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct bbl_inst { - unsigned int L; - int signed_immed_24; - unsigned int next_addr; - unsigned int jmp_addr; -}; - -struct bx_inst { - unsigned int Rm; -}; - -struct blx_inst { - union { - s32 signed_immed_24; - u32 Rm; - } val; - unsigned int inst; -}; - -struct clz_inst { - unsigned int Rm; - unsigned int Rd; -}; - -struct cps_inst { - unsigned int imod0; - unsigned int imod1; - unsigned int mmod; - unsigned int A, I, F; - unsigned int mode; -}; - -struct clrex_inst { -}; - -struct cpy_inst { - unsigned int Rm; - unsigned int Rd; -}; - -struct bic_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct sub_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct tst_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct cmn_inst { - unsigned int I; - unsigned int Rn; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct teq_inst { - unsigned int I; - unsigned int Rn; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct stm_inst { - unsigned int inst; -}; - -struct bkpt_inst { - u32 imm; -}; - -struct stc_inst { -}; - -struct ldc_inst { -}; - -struct swi_inst { - unsigned int num; -}; - -struct cmp_inst { - unsigned int I; - unsigned int Rn; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct mov_inst { - unsigned int I; - unsigned int S; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct mvn_inst { - unsigned int I; - unsigned int S; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct rev_inst { - unsigned int Rd; - unsigned int Rm; - unsigned int op1; - unsigned int op2; -}; - -struct rsb_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct rsc_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct sbc_inst { - unsigned int I; - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int shifter_operand; - shtop_fp_t shtop_func; -}; - -struct mul_inst { - unsigned int S; - unsigned int Rd; - unsigned int Rs; - unsigned int Rm; -}; - -struct smul_inst { - unsigned int Rd; - unsigned int Rs; - unsigned int Rm; - unsigned int x; - unsigned int y; -}; - -struct umull_inst { - unsigned int S; - unsigned int RdHi; - unsigned int RdLo; - unsigned int Rs; - unsigned int Rm; -}; - -struct smlad_inst { - unsigned int m; - unsigned int Rm; - unsigned int Rd; - unsigned int Ra; - unsigned int Rn; - unsigned int op1; - unsigned int op2; -}; - -struct smla_inst { - unsigned int x; - unsigned int y; - unsigned int Rm; - unsigned int Rd; - unsigned int Rs; - unsigned int Rn; -}; - -struct smlalxy_inst { - unsigned int x; - unsigned int y; - unsigned int RdLo; - unsigned int RdHi; - unsigned int Rm; - unsigned int Rn; -}; - -struct ssat_inst { - unsigned int Rn; - unsigned int Rd; - unsigned int imm5; - unsigned int sat_imm; - unsigned int shift_type; -}; - -struct umaal_inst { - unsigned int Rn; - unsigned int Rm; - unsigned int RdHi; - unsigned int RdLo; -}; - -struct umlal_inst { - unsigned int S; - unsigned int Rm; - unsigned int Rs; - unsigned int RdHi; - unsigned int RdLo; -}; - -struct smlal_inst { - unsigned int S; - unsigned int Rm; - unsigned int Rs; - unsigned int RdHi; - unsigned int RdLo; -}; - -struct smlald_inst { - unsigned int RdLo; - unsigned int RdHi; - unsigned int Rm; - unsigned int Rn; - unsigned int swap; - unsigned int op1; - unsigned int op2; -}; - -struct mla_inst { - unsigned int S; - unsigned int Rn; - unsigned int Rd; - unsigned int Rs; - unsigned int Rm; -}; - -struct mrc_inst { - unsigned int opcode_1; - unsigned int opcode_2; - unsigned int cp_num; - unsigned int crn; - unsigned int crm; - unsigned int Rd; - unsigned int inst; -}; - -struct mcr_inst { - unsigned int opcode_1; - unsigned int opcode_2; - unsigned int cp_num; - unsigned int crn; - unsigned int crm; - unsigned int Rd; - unsigned int inst; -}; - -struct mcrr_inst { - unsigned int opcode_1; - unsigned int cp_num; - unsigned int crm; - unsigned int rt; - unsigned int rt2; -}; - -struct mrs_inst { - unsigned int R; - unsigned int Rd; -}; - -struct msr_inst { - unsigned int field_mask; - unsigned int R; - unsigned int inst; -}; - -struct pld_inst { -}; - -struct sxtb_inst { - unsigned int Rd; - unsigned int Rm; - unsigned int rotate; -}; - -struct sxtab_inst { - unsigned int Rd; - unsigned int Rn; - unsigned int Rm; - unsigned rotate; -}; - -struct sxtah_inst { - unsigned int Rd; - unsigned int Rn; - unsigned int Rm; - unsigned int rotate; -}; - -struct sxth_inst { - unsigned int Rd; - unsigned int Rm; - unsigned int rotate; -}; - -struct uxtab_inst { - unsigned int Rn; - unsigned int Rd; - unsigned int rotate; - unsigned int Rm; -}; - -struct uxtah_inst { - unsigned int Rn; - unsigned int Rd; - unsigned int rotate; - unsigned int Rm; -}; - -struct uxth_inst { - unsigned int Rd; - unsigned int Rm; - unsigned int rotate; -}; - -struct cdp_inst { - unsigned int opcode_1; - unsigned int CRn; - unsigned int CRd; - unsigned int cp_num; - unsigned int opcode_2; - unsigned int CRm; - unsigned int inst; -}; - -struct uxtb_inst { - unsigned int Rd; - unsigned int Rm; - unsigned int rotate; -}; - -struct swp_inst { - unsigned int Rn; - unsigned int Rd; - unsigned int Rm; -}; - -struct setend_inst { - unsigned int set_bigend; -}; - -struct b_2_thumb { - unsigned int imm; -}; -struct b_cond_thumb { - unsigned int imm; - unsigned int cond; -}; - -struct bl_1_thumb { - unsigned int imm; -}; -struct bl_2_thumb { - unsigned int imm; -}; -struct blx_1_thumb { - unsigned int imm; - unsigned int instr; -}; - -struct pkh_inst { - unsigned int Rm; - unsigned int Rn; - unsigned int Rd; - unsigned char imm; -}; +#include "arm_dyncom_trans_struct.inc" typedef arm_inst * ARM_INST_PTR; @@ -1208,2200 +753,9 @@ static get_addr_fp_t get_calc_addr_op(unsigned int inst) { return nullptr; } -#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s) - -static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst)); - adc_inst *inst_cream = (adc_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst)); - add_inst *inst_cream = (add_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst)); - and_inst *inst_cream = (and_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) -{ - #define POSBRANCH ((inst & 0x7fffff) << 2) - #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2) - - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst)); - bbl_inst *inst_cream = (bbl_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; - - if (BIT(inst, 24)) - inst_base->br = CALL; - if (BITS(inst, 28, 31) <= 0xe) - inst_base->br |= COND; - - inst_cream->L = BIT(inst, 24); - inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst)); - bic_inst *inst_cream = (bic_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bkpt_inst)); - bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst)); - blx_inst *inst_cream = (blx_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = INDIRECT_BRANCH; - - inst_cream->inst = inst; - if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { - inst_cream->val.Rm = BITS(inst, 0, 3); - } else { - inst_cream->val.signed_immed_24 = BITS(inst, 0, 23); - } - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst)); - bx_inst *inst_cream = (bx_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = INDIRECT_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(bx)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index) { - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst)); - cdp_inst *inst_cream = (cdp_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->CRm = BITS(inst, 0, 3); - inst_cream->CRd = BITS(inst, 12, 15); - inst_cream->CRn = BITS(inst, 16, 19); - inst_cream->cp_num = BITS(inst, 8, 11); - inst_cream->opcode_2 = BITS(inst, 5, 7); - inst_cream->opcode_1 = BITS(inst, 20, 23); - inst_cream->inst = inst; - - LOG_TRACE(Core_ARM11, "inst %x index %x", inst, index); - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst)); - clz_inst *inst_cream = (clz_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rd = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst)); - cmn_inst *inst_cream = (cmn_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst)); - cmp_inst *inst_cream = (cmp_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst)); - cps_inst *inst_cream = (cps_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->imod0 = BIT(inst, 18); - inst_cream->imod1 = BIT(inst, 19); - inst_cream->mmod = BIT(inst, 17); - inst_cream->A = BIT(inst, 8); - inst_cream->I = BIT(inst, 7); - inst_cream->F = BIT(inst, 6); - inst_cream->mode = BITS(inst, 0, 4); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); - mov_inst *inst_cream = (mov_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) { - inst_base->br = INDIRECT_BRANCH; - } - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst)); - eor_inst *inst_cream = (eor_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - if (BIT(inst, 15)) { - inst_base->br = INDIRECT_BRANCH; - } - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); - sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->rotate = BITS(inst, 10, 11); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - if (BITS(inst, 12, 15) == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - if (BITS(inst, 12, 15) == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); - uxth_inst *inst_cream = (uxth_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst)); - uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) -{ - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst* inst_cream = (ldst_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - DEBUG_MSG; - } - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = (BITS(inst, 12, 15) == 15) ? INDIRECT_BRANCH : NON_BRANCH; // Branch if dest is R15 - - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(ldrex)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexh)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(ldrex)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexd)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(ldrex)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) -{ - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst* inst_cream = (ldst_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - // Reaching this would indicate the thumb version - // of this instruction, however the 3DS CPU doesn't - // support this variant (the 3DS CPU is only ARMv6K, - // while this variant is added in ARMv6T2). - // So it's sufficient for citra to not implement this. - DEBUG_MSG; - } - - if (BITS(inst, 12, 15) == 15) { - inst_base->br = INDIRECT_BRANCH; - } - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst)); - mcr_inst *inst_cream = (mcr_inst *)inst_base->component; - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->crn = BITS(inst, 16, 19); - inst_cream->crm = BITS(inst, 0, 3); - inst_cream->opcode_1 = BITS(inst, 21, 23); - inst_cream->opcode_2 = BITS(inst, 5, 7); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->cp_num = BITS(inst, 8, 11); - inst_cream->inst = inst; - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mcrr_inst)); - mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->crm = BITS(inst, 0, 3); - inst_cream->opcode_1 = BITS(inst, 4, 7); - inst_cream->cp_num = BITS(inst, 8, 11); - inst_cream->rt = BITS(inst, 12, 15); - inst_cream->rt2 = BITS(inst, 16, 19); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst)); - mla_inst *inst_cream = (mla_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 12, 15); - inst_cream->Rd = BITS(inst, 16, 19); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); - mov_inst *inst_cream = (mov_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) { - inst_base->br = INDIRECT_BRANCH; - } - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst)); - mrc_inst *inst_cream = (mrc_inst *)inst_base->component; - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->crn = BITS(inst, 16, 19); - inst_cream->crm = BITS(inst, 0, 3); - inst_cream->opcode_1 = BITS(inst, 21, 23); - inst_cream->opcode_2 = BITS(inst, 5, 7); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->cp_num = BITS(inst, 8, 11); - inst_cream->inst = inst; - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(mcrr)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst)); - mrs_inst *inst_cream = (mrs_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->R = BIT(inst, 22); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst)); - msr_inst *inst_cream = (msr_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->field_mask = BITS(inst, 16, 19); - inst_cream->R = BIT(inst, 22); - inst_cream->inst = inst; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst)); - mul_inst *inst_cream = (mul_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->S = BIT(inst, 20); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->Rd = BITS(inst, 16, 19); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst)); - mvn_inst *inst_cream = (mvn_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) { - inst_base->br = INDIRECT_BRANCH; - } - return inst_base; - -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst)); - orr_inst *inst_cream = (orr_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} - -// NOP introduced in ARMv6K. -static ARM_INST_PTR INTERPRETER_TRANSLATE(nop)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pkh_inst)); - pkh_inst *inst_cream = (pkh_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->imm = BITS(inst, 7, 11); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(pkhbt)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst)); - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->op1 = BITS(inst, 21, 22); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->op1 = BITS(inst, 20, 21); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(qadd8)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); - rev_inst* const inst_cream = (rev_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->op1 = BITS(inst, 20, 22); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(rev)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(rev)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; - - inst_base->cond = AL; - inst_base->idx = index; - inst_base->br = INDIRECT_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst)); - rsb_inst *inst_cream = (rsb_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst)); - rsc_inst *inst_cream = (rsc_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->op1 = BITS(inst, 20, 21); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(sadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(sadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(sadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(sadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(sadd8)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst)); - sbc_inst *inst_cream = (sbc_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->op1 = BITS(inst, 20, 22); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(setend_inst)); - setend_inst* const inst_cream = (setend_inst*)inst_base->component; - - inst_base->cond = AL; - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->set_bigend = BIT(inst, 9); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(sev)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->op1 = BITS(inst, 20, 21); - inst_cream->op2 = BITS(inst, 5, 7); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(shadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(shadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(shadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(shadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(shadd8)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst)); - smla_inst *inst_cream = (smla_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->x = BIT(inst, 5); - inst_cream->y = BIT(inst, 6); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->Rd = BITS(inst, 16, 19); - inst_cream->Rn = BITS(inst, 12, 15); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); - smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->m = BIT(inst, 5); - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->Rm = BITS(inst, 8, 11); - inst_cream->Rd = BITS(inst, 16, 19); - inst_cream->Ra = BITS(inst, 12, 15); - inst_cream->op1 = BITS(inst, 20, 22); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(smlad)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(smlad)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(smlad)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); - umlal_inst *inst_cream = (umlal_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->S = BIT(inst, 20); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->RdHi = BITS(inst, 16, 19); - inst_cream->RdLo = BITS(inst, 12, 15); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlalxy_inst)); - smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->x = BIT(inst, 5); - inst_cream->y = BIT(inst, 6); - inst_cream->RdLo = BITS(inst, 12, 15); - inst_cream->RdHi = BITS(inst, 16, 19); - inst_cream->Rn = BITS(inst, 0, 4); - inst_cream->Rm = BITS(inst, 8, 11); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); - smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Ra = BITS(inst, 12, 15); - inst_cream->Rm = BITS(inst, 8, 11); - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->Rd = BITS(inst, 16, 19); - inst_cream->m = BIT(inst, 6); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlald_inst)); - smlald_inst* const inst_cream = (smlald_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 8, 11); - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->RdLo = BITS(inst, 12, 15); - inst_cream->RdHi = BITS(inst, 16, 19); - inst_cream->swap = BIT(inst, 5); - inst_cream->op1 = BITS(inst, 20, 22); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(smlald)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); - smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->m = BIT(inst, 5); - inst_cream->Ra = BITS(inst, 12, 15); - inst_cream->Rm = BITS(inst, 8, 11); - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->Rd = BITS(inst, 16, 19); - inst_cream->op1 = BITS(inst, 20, 22); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(smmla)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(smmla)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst)); - smul_inst *inst_cream = (smul_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 16, 19); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->Rm = BITS(inst, 0, 3); - - inst_cream->x = BIT(inst, 5); - inst_cream->y = BIT(inst, 6); - - return inst_base; - -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); - umull_inst *inst_cream = (umull_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->S = BIT(inst, 20); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->RdHi = BITS(inst, 16, 19); - inst_cream->RdLo = BITS(inst, 12, 15); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); - smlad_inst *inst_cream = (smlad_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->m = BIT(inst, 6); - inst_cream->Rm = BITS(inst, 8, 11); - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->Rd = BITS(inst, 16, 19); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; - - inst_base->cond = AL; - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); - ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->imm5 = BITS(inst, 7, 11); - inst_cream->sat_imm = BITS(inst, 16, 20); - inst_cream->shift_type = BIT(inst, 6); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); - ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->sat_imm = BITS(inst, 16, 19); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); - sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->rotate = BITS(inst, 10, 11); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); - uxth_inst *inst_cream = (uxth_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); - uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) -{ - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst* inst_cream = (ldst_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - DEBUG_MSG; - } - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(strex)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strexh)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(strex)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strexd)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(strex)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) -{ - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); - ldst_inst* inst_cream = (ldst_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->inst = inst; - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - // Reaching this would indicate the thumb version - // of this instruction, however the 3DS CPU doesn't - // support this variant (the 3DS CPU is only ARMv6K, - // while this variant is added in ARMv6T2). - // So it's sufficient for citra to not implement this. - DEBUG_MSG; - } - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst)); - sub_inst *inst_cream = (sub_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst)); - swi_inst *inst_cream = (swi_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->num = BITS(inst, 0, 23); - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); - swp_inst *inst_cream = (swp_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); - swp_inst *inst_cream = (swp_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->Rm = BITS(inst, 0, 3); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); - sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); - sxtab_inst* const inst_cream = (sxtab_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(sxtab16)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index) { - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst)); - sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst)); - teq_inst *inst_cream = (teq_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst)); - tst_inst *inst_cream = (tst_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->I = BIT(inst, 25); - inst_cream->S = BIT(inst, 20); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->op1 = BITS(inst, 20, 21); - inst_cream->op2 = BITS(inst, 5, 7); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uadd8)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->op1 = BITS(inst, 20, 21); - inst_cream->op2 = BITS(inst, 5, 7); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uhadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uhadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uhadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uhadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uhadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst)); - umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 8, 11); - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->RdLo = BITS(inst, 12, 15); - inst_cream->RdHi = BITS(inst, 16, 19); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); - umlal_inst *inst_cream = (umlal_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->S = BIT(inst, 20); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->RdHi = BITS(inst, 16, 19); - inst_cream->RdLo = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); - umull_inst *inst_cream = (umull_inst *)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->S = BIT(inst, 20); - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rs = BITS(inst, 8, 11); - inst_cream->RdHi = BITS(inst, 16, 19); - inst_cream->RdLo = BITS(inst, 12, 15); - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb)); - b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; - - inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); - - inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb)); - b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; - - inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); - inst_cream->cond = ((tinst >> 8) & 0xf); - inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; - - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb)); - bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; - - inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); - - inst_base->idx = index; - inst_base->br = NON_BRANCH; - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb)); - bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; - - inst_cream->imm = (tinst & 0x07FF) << 1; - - inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) -{ - arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb)); - blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; - - inst_cream->imm = (tinst & 0x07FF) << 1; - inst_cream->instr = tinst; - - inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; - return inst_base; -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->op1 = BITS(inst, 20, 21); - inst_cream->op2 = BITS(inst, 5, 7); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uqadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uqadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uqadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uqadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uqadd8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); - generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->op1 = BITS(inst, 20, 24); - inst_cream->op2 = BITS(inst, 5, 7); - inst_cream->Rd = BITS(inst, 16, 19); - inst_cream->Rm = BITS(inst, 8, 11); - inst_cream->Rn = BITS(inst, 0, 3); - inst_cream->Ra = BITS(inst, 12, 15); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(usada8)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(ssat)(inst, index); -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(ssat16)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); - uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - inst_cream->Rm = BITS(inst, 0, 3); - inst_cream->Rn = BITS(inst, 16, 19); - inst_cream->Rd = BITS(inst, 12, 15); - inst_cream->rotate = BITS(inst, 10, 11); - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index) -{ - return INTERPRETER_TRANSLATE(uxtab16)(inst, index); -} - -static ARM_INST_PTR INTERPRETER_TRANSLATE(wfe)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(wfi)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} -static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) -{ - arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = NON_BRANCH; - - return inst_base; -} - -// Floating point VFPv3 structures and instructions - -#define VFP_INTERPRETER_STRUCT -#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" -#undef VFP_INTERPRETER_STRUCT - -#define VFP_INTERPRETER_TRANS -#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" -#undef VFP_INTERPRETER_TRANS - typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); -const transop_fp_t arm_instruction_trans[] = { - INTERPRETER_TRANSLATE(vmla), - INTERPRETER_TRANSLATE(vmls), - INTERPRETER_TRANSLATE(vnmla), - INTERPRETER_TRANSLATE(vnmls), - INTERPRETER_TRANSLATE(vnmul), - INTERPRETER_TRANSLATE(vmul), - INTERPRETER_TRANSLATE(vadd), - INTERPRETER_TRANSLATE(vsub), - INTERPRETER_TRANSLATE(vdiv), - INTERPRETER_TRANSLATE(vmovi), - INTERPRETER_TRANSLATE(vmovr), - INTERPRETER_TRANSLATE(vabs), - INTERPRETER_TRANSLATE(vneg), - INTERPRETER_TRANSLATE(vsqrt), - INTERPRETER_TRANSLATE(vcmp), - INTERPRETER_TRANSLATE(vcmp2), - INTERPRETER_TRANSLATE(vcvtbds), - INTERPRETER_TRANSLATE(vcvtbff), - INTERPRETER_TRANSLATE(vcvtbfi), - INTERPRETER_TRANSLATE(vmovbrs), - INTERPRETER_TRANSLATE(vmsr), - INTERPRETER_TRANSLATE(vmovbrc), - INTERPRETER_TRANSLATE(vmrs), - INTERPRETER_TRANSLATE(vmovbcr), - INTERPRETER_TRANSLATE(vmovbrrss), - INTERPRETER_TRANSLATE(vmovbrrd), - INTERPRETER_TRANSLATE(vstr), - INTERPRETER_TRANSLATE(vpush), - INTERPRETER_TRANSLATE(vstm), - INTERPRETER_TRANSLATE(vpop), - INTERPRETER_TRANSLATE(vldr), - INTERPRETER_TRANSLATE(vldm), - - INTERPRETER_TRANSLATE(srs), - INTERPRETER_TRANSLATE(rfe), - INTERPRETER_TRANSLATE(bkpt), - INTERPRETER_TRANSLATE(blx), - INTERPRETER_TRANSLATE(cps), - INTERPRETER_TRANSLATE(pld), - INTERPRETER_TRANSLATE(setend), - INTERPRETER_TRANSLATE(clrex), - INTERPRETER_TRANSLATE(rev16), - INTERPRETER_TRANSLATE(usad8), - INTERPRETER_TRANSLATE(sxtb), - INTERPRETER_TRANSLATE(uxtb), - INTERPRETER_TRANSLATE(sxth), - INTERPRETER_TRANSLATE(sxtb16), - INTERPRETER_TRANSLATE(uxth), - INTERPRETER_TRANSLATE(uxtb16), - INTERPRETER_TRANSLATE(cpy), - INTERPRETER_TRANSLATE(uxtab), - INTERPRETER_TRANSLATE(ssub8), - INTERPRETER_TRANSLATE(shsub8), - INTERPRETER_TRANSLATE(ssubaddx), - INTERPRETER_TRANSLATE(strex), - INTERPRETER_TRANSLATE(strexb), - INTERPRETER_TRANSLATE(swp), - INTERPRETER_TRANSLATE(swpb), - INTERPRETER_TRANSLATE(ssub16), - INTERPRETER_TRANSLATE(ssat16), - INTERPRETER_TRANSLATE(shsubaddx), - INTERPRETER_TRANSLATE(qsubaddx), - INTERPRETER_TRANSLATE(shaddsubx), - INTERPRETER_TRANSLATE(shadd8), - INTERPRETER_TRANSLATE(shadd16), - INTERPRETER_TRANSLATE(sel), - INTERPRETER_TRANSLATE(saddsubx), - INTERPRETER_TRANSLATE(sadd8), - INTERPRETER_TRANSLATE(sadd16), - INTERPRETER_TRANSLATE(shsub16), - INTERPRETER_TRANSLATE(umaal), - INTERPRETER_TRANSLATE(uxtab16), - INTERPRETER_TRANSLATE(usubaddx), - INTERPRETER_TRANSLATE(usub8), - INTERPRETER_TRANSLATE(usub16), - INTERPRETER_TRANSLATE(usat16), - INTERPRETER_TRANSLATE(usada8), - INTERPRETER_TRANSLATE(uqsubaddx), - INTERPRETER_TRANSLATE(uqsub8), - INTERPRETER_TRANSLATE(uqsub16), - INTERPRETER_TRANSLATE(uqaddsubx), - INTERPRETER_TRANSLATE(uqadd8), - INTERPRETER_TRANSLATE(uqadd16), - INTERPRETER_TRANSLATE(sxtab), - INTERPRETER_TRANSLATE(uhsubaddx), - INTERPRETER_TRANSLATE(uhsub8), - INTERPRETER_TRANSLATE(uhsub16), - INTERPRETER_TRANSLATE(uhaddsubx), - INTERPRETER_TRANSLATE(uhadd8), - INTERPRETER_TRANSLATE(uhadd16), - INTERPRETER_TRANSLATE(uaddsubx), - INTERPRETER_TRANSLATE(uadd8), - INTERPRETER_TRANSLATE(uadd16), - INTERPRETER_TRANSLATE(sxtah), - INTERPRETER_TRANSLATE(sxtab16), - INTERPRETER_TRANSLATE(qadd8), - INTERPRETER_TRANSLATE(bxj), - INTERPRETER_TRANSLATE(clz), - INTERPRETER_TRANSLATE(uxtah), - INTERPRETER_TRANSLATE(bx), - INTERPRETER_TRANSLATE(rev), - INTERPRETER_TRANSLATE(blx), - INTERPRETER_TRANSLATE(revsh), - INTERPRETER_TRANSLATE(qadd), - INTERPRETER_TRANSLATE(qadd16), - INTERPRETER_TRANSLATE(qaddsubx), - INTERPRETER_TRANSLATE(ldrex), - INTERPRETER_TRANSLATE(qdadd), - INTERPRETER_TRANSLATE(qdsub), - INTERPRETER_TRANSLATE(qsub), - INTERPRETER_TRANSLATE(ldrexb), - INTERPRETER_TRANSLATE(qsub8), - INTERPRETER_TRANSLATE(qsub16), - INTERPRETER_TRANSLATE(smuad), - INTERPRETER_TRANSLATE(smmul), - INTERPRETER_TRANSLATE(smusd), - INTERPRETER_TRANSLATE(smlsd), - INTERPRETER_TRANSLATE(smlsld), - INTERPRETER_TRANSLATE(smmla), - INTERPRETER_TRANSLATE(smmls), - INTERPRETER_TRANSLATE(smlald), - INTERPRETER_TRANSLATE(smlad), - INTERPRETER_TRANSLATE(smlaw), - INTERPRETER_TRANSLATE(smulw), - INTERPRETER_TRANSLATE(pkhtb), - INTERPRETER_TRANSLATE(pkhbt), - INTERPRETER_TRANSLATE(smul), - INTERPRETER_TRANSLATE(smlalxy), - INTERPRETER_TRANSLATE(smla), - INTERPRETER_TRANSLATE(mcrr), - INTERPRETER_TRANSLATE(mrrc), - INTERPRETER_TRANSLATE(cmp), - INTERPRETER_TRANSLATE(tst), - INTERPRETER_TRANSLATE(teq), - INTERPRETER_TRANSLATE(cmn), - INTERPRETER_TRANSLATE(smull), - INTERPRETER_TRANSLATE(umull), - INTERPRETER_TRANSLATE(umlal), - INTERPRETER_TRANSLATE(smlal), - INTERPRETER_TRANSLATE(mul), - INTERPRETER_TRANSLATE(mla), - INTERPRETER_TRANSLATE(ssat), - INTERPRETER_TRANSLATE(usat), - INTERPRETER_TRANSLATE(mrs), - INTERPRETER_TRANSLATE(msr), - INTERPRETER_TRANSLATE(and), - INTERPRETER_TRANSLATE(bic), - INTERPRETER_TRANSLATE(ldm), - INTERPRETER_TRANSLATE(eor), - INTERPRETER_TRANSLATE(add), - INTERPRETER_TRANSLATE(rsb), - INTERPRETER_TRANSLATE(rsc), - INTERPRETER_TRANSLATE(sbc), - INTERPRETER_TRANSLATE(adc), - INTERPRETER_TRANSLATE(sub), - INTERPRETER_TRANSLATE(orr), - INTERPRETER_TRANSLATE(mvn), - INTERPRETER_TRANSLATE(mov), - INTERPRETER_TRANSLATE(stm), - INTERPRETER_TRANSLATE(ldm), - INTERPRETER_TRANSLATE(ldrsh), - INTERPRETER_TRANSLATE(stm), - INTERPRETER_TRANSLATE(ldm), - INTERPRETER_TRANSLATE(ldrsb), - INTERPRETER_TRANSLATE(strd), - INTERPRETER_TRANSLATE(ldrh), - INTERPRETER_TRANSLATE(strh), - INTERPRETER_TRANSLATE(ldrd), - INTERPRETER_TRANSLATE(strt), - INTERPRETER_TRANSLATE(strbt), - INTERPRETER_TRANSLATE(ldrbt), - INTERPRETER_TRANSLATE(ldrt), - INTERPRETER_TRANSLATE(mrc), - INTERPRETER_TRANSLATE(mcr), - INTERPRETER_TRANSLATE(msr), - INTERPRETER_TRANSLATE(msr), - INTERPRETER_TRANSLATE(msr), - INTERPRETER_TRANSLATE(msr), - INTERPRETER_TRANSLATE(msr), - INTERPRETER_TRANSLATE(ldrb), - INTERPRETER_TRANSLATE(strb), - INTERPRETER_TRANSLATE(ldr), - INTERPRETER_TRANSLATE(ldrcond), - INTERPRETER_TRANSLATE(str), - INTERPRETER_TRANSLATE(cdp), - INTERPRETER_TRANSLATE(stc), - INTERPRETER_TRANSLATE(ldc), - INTERPRETER_TRANSLATE(ldrexd), - INTERPRETER_TRANSLATE(strexd), - INTERPRETER_TRANSLATE(ldrexh), - INTERPRETER_TRANSLATE(strexh), - INTERPRETER_TRANSLATE(nop), - INTERPRETER_TRANSLATE(yield), - INTERPRETER_TRANSLATE(wfe), - INTERPRETER_TRANSLATE(wfi), - INTERPRETER_TRANSLATE(sev), - INTERPRETER_TRANSLATE(swi), - INTERPRETER_TRANSLATE(bbl), - - // All the thumb instructions should be placed the end of table - INTERPRETER_TRANSLATE(b_2_thumb), - INTERPRETER_TRANSLATE(b_cond_thumb), - INTERPRETER_TRANSLATE(bl_1_thumb), - INTERPRETER_TRANSLATE(bl_2_thumb), - INTERPRETER_TRANSLATE(blx_1_thumb) -}; +#include "arm_dyncom_trans.inc" enum { FETCH_SUCCESS, diff --git a/src/core/arm/dyncom/arm_dyncom_trans.inc b/src/core/arm/dyncom/arm_dyncom_trans.inc new file mode 100644 index 000000000..b4bf79240 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_trans.inc @@ -0,0 +1,2188 @@ +#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s) + +static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst)); + adc_inst *inst_cream = (adc_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst)); + add_inst *inst_cream = (add_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst)); + and_inst *inst_cream = (and_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) +{ + #define POSBRANCH ((inst & 0x7fffff) << 2) + #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2) + + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst)); + bbl_inst *inst_cream = (bbl_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + + if (BIT(inst, 24)) + inst_base->br = CALL; + if (BITS(inst, 28, 31) <= 0xe) + inst_base->br |= COND; + + inst_cream->L = BIT(inst, 24); + inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst)); + bic_inst *inst_cream = (bic_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bkpt_inst)); + bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst)); + blx_inst *inst_cream = (blx_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = INDIRECT_BRANCH; + + inst_cream->inst = inst; + if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { + inst_cream->val.Rm = BITS(inst, 0, 3); + } else { + inst_cream->val.signed_immed_24 = BITS(inst, 0, 23); + } + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst)); + bx_inst *inst_cream = (bx_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = INDIRECT_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(bx)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index) { + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst)); + cdp_inst *inst_cream = (cdp_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->CRm = BITS(inst, 0, 3); + inst_cream->CRd = BITS(inst, 12, 15); + inst_cream->CRn = BITS(inst, 16, 19); + inst_cream->cp_num = BITS(inst, 8, 11); + inst_cream->opcode_2 = BITS(inst, 5, 7); + inst_cream->opcode_1 = BITS(inst, 20, 23); + inst_cream->inst = inst; + + LOG_TRACE(Core_ARM11, "inst %x index %x", inst, index); + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst)); + clz_inst *inst_cream = (clz_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst)); + cmn_inst *inst_cream = (cmn_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst)); + cmp_inst *inst_cream = (cmp_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst)); + cps_inst *inst_cream = (cps_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->imod0 = BIT(inst, 18); + inst_cream->imod1 = BIT(inst, 19); + inst_cream->mmod = BIT(inst, 17); + inst_cream->A = BIT(inst, 8); + inst_cream->I = BIT(inst, 7); + inst_cream->F = BIT(inst, 6); + inst_cream->mode = BITS(inst, 0, 4); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); + mov_inst *inst_cream = (mov_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst)); + eor_inst *inst_cream = (eor_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BIT(inst, 15)) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); + sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->rotate = BITS(inst, 10, 11); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); + uxth_inst *inst_cream = (uxth_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst)); + uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) +{ + arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + if (BITS(inst, 25, 27) == 2) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else if (BITS(inst, 25, 27) == 3) { + inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); + } else { + DEBUG_MSG; + } + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = (BITS(inst, 12, 15) == 15) ? INDIRECT_BRANCH : NON_BRANCH; // Branch if dest is R15 + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(ldrex)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexh)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(ldrex)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexd)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(ldrex)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) +{ + arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + if (BITS(inst, 25, 27) == 2) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else if (BITS(inst, 25, 27) == 3) { + inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); + } else { + // Reaching this would indicate the thumb version + // of this instruction, however the 3DS CPU doesn't + // support this variant (the 3DS CPU is only ARMv6K, + // while this variant is added in ARMv6T2). + // So it's sufficient for citra to not implement this. + DEBUG_MSG; + } + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst)); + mcr_inst *inst_cream = (mcr_inst *)inst_base->component; + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->crn = BITS(inst, 16, 19); + inst_cream->crm = BITS(inst, 0, 3); + inst_cream->opcode_1 = BITS(inst, 21, 23); + inst_cream->opcode_2 = BITS(inst, 5, 7); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->cp_num = BITS(inst, 8, 11); + inst_cream->inst = inst; + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mcrr_inst)); + mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->crm = BITS(inst, 0, 3); + inst_cream->opcode_1 = BITS(inst, 4, 7); + inst_cream->cp_num = BITS(inst, 8, 11); + inst_cream->rt = BITS(inst, 12, 15); + inst_cream->rt2 = BITS(inst, 16, 19); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst)); + mla_inst *inst_cream = (mla_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 12, 15); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); + mov_inst *inst_cream = (mov_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst)); + mrc_inst *inst_cream = (mrc_inst *)inst_base->component; + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->crn = BITS(inst, 16, 19); + inst_cream->crm = BITS(inst, 0, 3); + inst_cream->opcode_1 = BITS(inst, 21, 23); + inst_cream->opcode_2 = BITS(inst, 5, 7); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->cp_num = BITS(inst, 8, 11); + inst_cream->inst = inst; + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(mcrr)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst)); + mrs_inst *inst_cream = (mrs_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->R = BIT(inst, 22); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst)); + msr_inst *inst_cream = (msr_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->field_mask = BITS(inst, 16, 19); + inst_cream->R = BIT(inst, 22); + inst_cream->inst = inst; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst)); + mul_inst *inst_cream = (mul_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rd = BITS(inst, 16, 19); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst)); + mvn_inst *inst_cream = (mvn_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; + +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst)); + orr_inst *inst_cream = (orr_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} + +// NOP introduced in ARMv6K. +static ARM_INST_PTR INTERPRETER_TRANSLATE(nop)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pkh_inst)); + pkh_inst *inst_cream = (pkh_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->imm = BITS(inst, 7, 11); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(pkhbt)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->op1 = BITS(inst, 21, 22); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->op1 = BITS(inst, 20, 21); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(qadd8)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); + rev_inst* const inst_cream = (rev_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->op1 = BITS(inst, 20, 22); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(rev)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(rev)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = AL; + inst_base->idx = index; + inst_base->br = INDIRECT_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst)); + rsb_inst *inst_cream = (rsb_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst)); + rsc_inst *inst_cream = (rsc_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->op1 = BITS(inst, 20, 21); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(sadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(sadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(sadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(sadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(sadd8)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst)); + sbc_inst *inst_cream = (sbc_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->op1 = BITS(inst, 20, 22); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(setend_inst)); + setend_inst* const inst_cream = (setend_inst*)inst_base->component; + + inst_base->cond = AL; + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->set_bigend = BIT(inst, 9); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(sev)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->op1 = BITS(inst, 20, 21); + inst_cream->op2 = BITS(inst, 5, 7); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(shadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(shadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(shadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(shadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(shadd8)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst)); + smla_inst *inst_cream = (smla_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->x = BIT(inst, 5); + inst_cream->y = BIT(inst, 6); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Rn = BITS(inst, 12, 15); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); + smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->m = BIT(inst, 5); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Ra = BITS(inst, 12, 15); + inst_cream->op1 = BITS(inst, 20, 22); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(smlad)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(smlad)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(smlad)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); + umlal_inst *inst_cream = (umlal_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlalxy_inst)); + smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->x = BIT(inst, 5); + inst_cream->y = BIT(inst, 6); + inst_cream->RdLo = BITS(inst, 12, 15); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->Rn = BITS(inst, 0, 4); + inst_cream->Rm = BITS(inst, 8, 11); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); + smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Ra = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->m = BIT(inst, 6); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlald_inst)); + smlald_inst* const inst_cream = (smlald_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->RdLo = BITS(inst, 12, 15); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->swap = BIT(inst, 5); + inst_cream->op1 = BITS(inst, 20, 22); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(smlald)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); + smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->m = BIT(inst, 5); + inst_cream->Ra = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->op1 = BITS(inst, 20, 22); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(smmla)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(smmla)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst)); + smul_inst *inst_cream = (smul_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + inst_cream->x = BIT(inst, 5); + inst_cream->y = BIT(inst, 6); + + return inst_base; + +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); + umull_inst *inst_cream = (umull_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); + smlad_inst *inst_cream = (smlad_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->m = BIT(inst, 6); + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 16, 19); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = AL; + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); + ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->imm5 = BITS(inst, 7, 11); + inst_cream->sat_imm = BITS(inst, 16, 20); + inst_cream->shift_type = BIT(inst, 6); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); + ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->sat_imm = BITS(inst, 16, 19); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); + sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->rotate = BITS(inst, 10, 11); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); + uxth_inst *inst_cream = (uxth_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); + uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) +{ + arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + + if (BITS(inst, 25, 27) == 2) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else if (BITS(inst, 25, 27) == 3) { + inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); + } else { + DEBUG_MSG; + } + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(strex)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strexh)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(strex)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strexd)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(strex)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) +{ + arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + if (BITS(inst, 25, 27) == 2) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else if (BITS(inst, 25, 27) == 3) { + inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); + } else { + // Reaching this would indicate the thumb version + // of this instruction, however the 3DS CPU doesn't + // support this variant (the 3DS CPU is only ARMv6K, + // while this variant is added in ARMv6T2). + // So it's sufficient for citra to not implement this. + DEBUG_MSG; + } + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst)); + sub_inst *inst_cream = (sub_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst)); + swi_inst *inst_cream = (swi_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->num = BITS(inst, 0, 23); + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); + swp_inst *inst_cream = (swp_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); + swp_inst *inst_cream = (swp_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); + sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); + sxtab_inst* const inst_cream = (sxtab_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(sxtab16)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index) { + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst)); + sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst)); + teq_inst *inst_cream = (teq_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst)); + tst_inst *inst_cream = (tst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->op1 = BITS(inst, 20, 21); + inst_cream->op2 = BITS(inst, 5, 7); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uadd8)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->op1 = BITS(inst, 20, 21); + inst_cream->op2 = BITS(inst, 5, 7); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uhadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uhadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uhadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uhadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uhadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst)); + umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->RdLo = BITS(inst, 12, 15); + inst_cream->RdHi = BITS(inst, 16, 19); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); + umlal_inst *inst_cream = (umlal_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); + umull_inst *inst_cream = (umull_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb)); + b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; + + inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); + + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb)); + b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; + + inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); + inst_cream->cond = ((tinst >> 8) & 0xf); + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb)); + bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; + + inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); + + inst_base->idx = index; + inst_base->br = NON_BRANCH; + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb)); + bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; + + inst_cream->imm = (tinst & 0x07FF) << 1; + + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb)); + blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; + + inst_cream->imm = (tinst & 0x07FF) << 1; + inst_cream->instr = tinst; + + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + return inst_base; +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->op1 = BITS(inst, 20, 21); + inst_cream->op2 = BITS(inst, 5, 7); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uqadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uqadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uqadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uqadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uqadd8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); + generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->op1 = BITS(inst, 20, 24); + inst_cream->op2 = BITS(inst, 5, 7); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Ra = BITS(inst, 12, 15); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(usada8)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(ssat)(inst, index); +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(ssat16)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); + uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index) +{ + return INTERPRETER_TRANSLATE(uxtab16)(inst, index); +} + +static ARM_INST_PTR INTERPRETER_TRANSLATE(wfe)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(wfi)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} + +// Floating point VFPv3 instructions + +#define VFP_INTERPRETER_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_INTERPRETER_TRANS + +const transop_fp_t arm_instruction_trans[] = { + INTERPRETER_TRANSLATE(vmla), + INTERPRETER_TRANSLATE(vmls), + INTERPRETER_TRANSLATE(vnmla), + INTERPRETER_TRANSLATE(vnmls), + INTERPRETER_TRANSLATE(vnmul), + INTERPRETER_TRANSLATE(vmul), + INTERPRETER_TRANSLATE(vadd), + INTERPRETER_TRANSLATE(vsub), + INTERPRETER_TRANSLATE(vdiv), + INTERPRETER_TRANSLATE(vmovi), + INTERPRETER_TRANSLATE(vmovr), + INTERPRETER_TRANSLATE(vabs), + INTERPRETER_TRANSLATE(vneg), + INTERPRETER_TRANSLATE(vsqrt), + INTERPRETER_TRANSLATE(vcmp), + INTERPRETER_TRANSLATE(vcmp2), + INTERPRETER_TRANSLATE(vcvtbds), + INTERPRETER_TRANSLATE(vcvtbff), + INTERPRETER_TRANSLATE(vcvtbfi), + INTERPRETER_TRANSLATE(vmovbrs), + INTERPRETER_TRANSLATE(vmsr), + INTERPRETER_TRANSLATE(vmovbrc), + INTERPRETER_TRANSLATE(vmrs), + INTERPRETER_TRANSLATE(vmovbcr), + INTERPRETER_TRANSLATE(vmovbrrss), + INTERPRETER_TRANSLATE(vmovbrrd), + INTERPRETER_TRANSLATE(vstr), + INTERPRETER_TRANSLATE(vpush), + INTERPRETER_TRANSLATE(vstm), + INTERPRETER_TRANSLATE(vpop), + INTERPRETER_TRANSLATE(vldr), + INTERPRETER_TRANSLATE(vldm), + + INTERPRETER_TRANSLATE(srs), + INTERPRETER_TRANSLATE(rfe), + INTERPRETER_TRANSLATE(bkpt), + INTERPRETER_TRANSLATE(blx), + INTERPRETER_TRANSLATE(cps), + INTERPRETER_TRANSLATE(pld), + INTERPRETER_TRANSLATE(setend), + INTERPRETER_TRANSLATE(clrex), + INTERPRETER_TRANSLATE(rev16), + INTERPRETER_TRANSLATE(usad8), + INTERPRETER_TRANSLATE(sxtb), + INTERPRETER_TRANSLATE(uxtb), + INTERPRETER_TRANSLATE(sxth), + INTERPRETER_TRANSLATE(sxtb16), + INTERPRETER_TRANSLATE(uxth), + INTERPRETER_TRANSLATE(uxtb16), + INTERPRETER_TRANSLATE(cpy), + INTERPRETER_TRANSLATE(uxtab), + INTERPRETER_TRANSLATE(ssub8), + INTERPRETER_TRANSLATE(shsub8), + INTERPRETER_TRANSLATE(ssubaddx), + INTERPRETER_TRANSLATE(strex), + INTERPRETER_TRANSLATE(strexb), + INTERPRETER_TRANSLATE(swp), + INTERPRETER_TRANSLATE(swpb), + INTERPRETER_TRANSLATE(ssub16), + INTERPRETER_TRANSLATE(ssat16), + INTERPRETER_TRANSLATE(shsubaddx), + INTERPRETER_TRANSLATE(qsubaddx), + INTERPRETER_TRANSLATE(shaddsubx), + INTERPRETER_TRANSLATE(shadd8), + INTERPRETER_TRANSLATE(shadd16), + INTERPRETER_TRANSLATE(sel), + INTERPRETER_TRANSLATE(saddsubx), + INTERPRETER_TRANSLATE(sadd8), + INTERPRETER_TRANSLATE(sadd16), + INTERPRETER_TRANSLATE(shsub16), + INTERPRETER_TRANSLATE(umaal), + INTERPRETER_TRANSLATE(uxtab16), + INTERPRETER_TRANSLATE(usubaddx), + INTERPRETER_TRANSLATE(usub8), + INTERPRETER_TRANSLATE(usub16), + INTERPRETER_TRANSLATE(usat16), + INTERPRETER_TRANSLATE(usada8), + INTERPRETER_TRANSLATE(uqsubaddx), + INTERPRETER_TRANSLATE(uqsub8), + INTERPRETER_TRANSLATE(uqsub16), + INTERPRETER_TRANSLATE(uqaddsubx), + INTERPRETER_TRANSLATE(uqadd8), + INTERPRETER_TRANSLATE(uqadd16), + INTERPRETER_TRANSLATE(sxtab), + INTERPRETER_TRANSLATE(uhsubaddx), + INTERPRETER_TRANSLATE(uhsub8), + INTERPRETER_TRANSLATE(uhsub16), + INTERPRETER_TRANSLATE(uhaddsubx), + INTERPRETER_TRANSLATE(uhadd8), + INTERPRETER_TRANSLATE(uhadd16), + INTERPRETER_TRANSLATE(uaddsubx), + INTERPRETER_TRANSLATE(uadd8), + INTERPRETER_TRANSLATE(uadd16), + INTERPRETER_TRANSLATE(sxtah), + INTERPRETER_TRANSLATE(sxtab16), + INTERPRETER_TRANSLATE(qadd8), + INTERPRETER_TRANSLATE(bxj), + INTERPRETER_TRANSLATE(clz), + INTERPRETER_TRANSLATE(uxtah), + INTERPRETER_TRANSLATE(bx), + INTERPRETER_TRANSLATE(rev), + INTERPRETER_TRANSLATE(blx), + INTERPRETER_TRANSLATE(revsh), + INTERPRETER_TRANSLATE(qadd), + INTERPRETER_TRANSLATE(qadd16), + INTERPRETER_TRANSLATE(qaddsubx), + INTERPRETER_TRANSLATE(ldrex), + INTERPRETER_TRANSLATE(qdadd), + INTERPRETER_TRANSLATE(qdsub), + INTERPRETER_TRANSLATE(qsub), + INTERPRETER_TRANSLATE(ldrexb), + INTERPRETER_TRANSLATE(qsub8), + INTERPRETER_TRANSLATE(qsub16), + INTERPRETER_TRANSLATE(smuad), + INTERPRETER_TRANSLATE(smmul), + INTERPRETER_TRANSLATE(smusd), + INTERPRETER_TRANSLATE(smlsd), + INTERPRETER_TRANSLATE(smlsld), + INTERPRETER_TRANSLATE(smmla), + INTERPRETER_TRANSLATE(smmls), + INTERPRETER_TRANSLATE(smlald), + INTERPRETER_TRANSLATE(smlad), + INTERPRETER_TRANSLATE(smlaw), + INTERPRETER_TRANSLATE(smulw), + INTERPRETER_TRANSLATE(pkhtb), + INTERPRETER_TRANSLATE(pkhbt), + INTERPRETER_TRANSLATE(smul), + INTERPRETER_TRANSLATE(smlalxy), + INTERPRETER_TRANSLATE(smla), + INTERPRETER_TRANSLATE(mcrr), + INTERPRETER_TRANSLATE(mrrc), + INTERPRETER_TRANSLATE(cmp), + INTERPRETER_TRANSLATE(tst), + INTERPRETER_TRANSLATE(teq), + INTERPRETER_TRANSLATE(cmn), + INTERPRETER_TRANSLATE(smull), + INTERPRETER_TRANSLATE(umull), + INTERPRETER_TRANSLATE(umlal), + INTERPRETER_TRANSLATE(smlal), + INTERPRETER_TRANSLATE(mul), + INTERPRETER_TRANSLATE(mla), + INTERPRETER_TRANSLATE(ssat), + INTERPRETER_TRANSLATE(usat), + INTERPRETER_TRANSLATE(mrs), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(and), + INTERPRETER_TRANSLATE(bic), + INTERPRETER_TRANSLATE(ldm), + INTERPRETER_TRANSLATE(eor), + INTERPRETER_TRANSLATE(add), + INTERPRETER_TRANSLATE(rsb), + INTERPRETER_TRANSLATE(rsc), + INTERPRETER_TRANSLATE(sbc), + INTERPRETER_TRANSLATE(adc), + INTERPRETER_TRANSLATE(sub), + INTERPRETER_TRANSLATE(orr), + INTERPRETER_TRANSLATE(mvn), + INTERPRETER_TRANSLATE(mov), + INTERPRETER_TRANSLATE(stm), + INTERPRETER_TRANSLATE(ldm), + INTERPRETER_TRANSLATE(ldrsh), + INTERPRETER_TRANSLATE(stm), + INTERPRETER_TRANSLATE(ldm), + INTERPRETER_TRANSLATE(ldrsb), + INTERPRETER_TRANSLATE(strd), + INTERPRETER_TRANSLATE(ldrh), + INTERPRETER_TRANSLATE(strh), + INTERPRETER_TRANSLATE(ldrd), + INTERPRETER_TRANSLATE(strt), + INTERPRETER_TRANSLATE(strbt), + INTERPRETER_TRANSLATE(ldrbt), + INTERPRETER_TRANSLATE(ldrt), + INTERPRETER_TRANSLATE(mrc), + INTERPRETER_TRANSLATE(mcr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(ldrb), + INTERPRETER_TRANSLATE(strb), + INTERPRETER_TRANSLATE(ldr), + INTERPRETER_TRANSLATE(ldrcond), + INTERPRETER_TRANSLATE(str), + INTERPRETER_TRANSLATE(cdp), + INTERPRETER_TRANSLATE(stc), + INTERPRETER_TRANSLATE(ldc), + INTERPRETER_TRANSLATE(ldrexd), + INTERPRETER_TRANSLATE(strexd), + INTERPRETER_TRANSLATE(ldrexh), + INTERPRETER_TRANSLATE(strexh), + INTERPRETER_TRANSLATE(nop), + INTERPRETER_TRANSLATE(yield), + INTERPRETER_TRANSLATE(wfe), + INTERPRETER_TRANSLATE(wfi), + INTERPRETER_TRANSLATE(sev), + INTERPRETER_TRANSLATE(swi), + INTERPRETER_TRANSLATE(bbl), + + // All the thumb instructions should be placed the end of table + INTERPRETER_TRANSLATE(b_2_thumb), + INTERPRETER_TRANSLATE(b_cond_thumb), + INTERPRETER_TRANSLATE(bl_1_thumb), + INTERPRETER_TRANSLATE(bl_2_thumb), + INTERPRETER_TRANSLATE(blx_1_thumb) +}; \ No newline at end of file diff --git a/src/core/arm/dyncom/arm_dyncom_trans_struct.inc b/src/core/arm/dyncom/arm_dyncom_trans_struct.inc new file mode 100644 index 000000000..0a7f3ab6e --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_trans_struct.inc @@ -0,0 +1,462 @@ +struct arm_inst { + unsigned int idx; + unsigned int cond; + int br; + char component[0]; +}; + +struct generic_arm_inst { + u32 Ra; + u32 Rm; + u32 Rn; + u32 Rd; + u8 op1; + u8 op2; +}; + +struct adc_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct add_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct orr_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct and_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct eor_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct bbl_inst { + unsigned int L; + int signed_immed_24; + unsigned int next_addr; + unsigned int jmp_addr; +}; + +struct bx_inst { + unsigned int Rm; +}; + +struct blx_inst { + union { + s32 signed_immed_24; + u32 Rm; + } val; + unsigned int inst; +}; + +struct clz_inst { + unsigned int Rm; + unsigned int Rd; +}; + +struct cps_inst { + unsigned int imod0; + unsigned int imod1; + unsigned int mmod; + unsigned int A, I, F; + unsigned int mode; +}; + +struct clrex_inst { +}; + +struct cpy_inst { + unsigned int Rm; + unsigned int Rd; +}; + +struct bic_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct sub_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct tst_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct cmn_inst { + unsigned int I; + unsigned int Rn; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct teq_inst { + unsigned int I; + unsigned int Rn; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct stm_inst { + unsigned int inst; +}; + +struct bkpt_inst { + u32 imm; +}; + +struct stc_inst { +}; + +struct ldc_inst { +}; + +struct swi_inst { + unsigned int num; +}; + +struct cmp_inst { + unsigned int I; + unsigned int Rn; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct mov_inst { + unsigned int I; + unsigned int S; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct mvn_inst { + unsigned int I; + unsigned int S; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct rev_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int op1; + unsigned int op2; +}; + +struct rsb_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct rsc_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct sbc_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +}; + +struct mul_inst { + unsigned int S; + unsigned int Rd; + unsigned int Rs; + unsigned int Rm; +}; + +struct smul_inst { + unsigned int Rd; + unsigned int Rs; + unsigned int Rm; + unsigned int x; + unsigned int y; +}; + +struct umull_inst { + unsigned int S; + unsigned int RdHi; + unsigned int RdLo; + unsigned int Rs; + unsigned int Rm; +}; + +struct smlad_inst { + unsigned int m; + unsigned int Rm; + unsigned int Rd; + unsigned int Ra; + unsigned int Rn; + unsigned int op1; + unsigned int op2; +}; + +struct smla_inst { + unsigned int x; + unsigned int y; + unsigned int Rm; + unsigned int Rd; + unsigned int Rs; + unsigned int Rn; +}; + +struct smlalxy_inst { + unsigned int x; + unsigned int y; + unsigned int RdLo; + unsigned int RdHi; + unsigned int Rm; + unsigned int Rn; +}; + +struct ssat_inst { + unsigned int Rn; + unsigned int Rd; + unsigned int imm5; + unsigned int sat_imm; + unsigned int shift_type; +}; + +struct umaal_inst { + unsigned int Rn; + unsigned int Rm; + unsigned int RdHi; + unsigned int RdLo; +}; + +struct umlal_inst { + unsigned int S; + unsigned int Rm; + unsigned int Rs; + unsigned int RdHi; + unsigned int RdLo; +}; + +struct smlal_inst { + unsigned int S; + unsigned int Rm; + unsigned int Rs; + unsigned int RdHi; + unsigned int RdLo; +}; + +struct smlald_inst { + unsigned int RdLo; + unsigned int RdHi; + unsigned int Rm; + unsigned int Rn; + unsigned int swap; + unsigned int op1; + unsigned int op2; +}; + +struct mla_inst { + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int Rs; + unsigned int Rm; +}; + +struct mrc_inst { + unsigned int opcode_1; + unsigned int opcode_2; + unsigned int cp_num; + unsigned int crn; + unsigned int crm; + unsigned int Rd; + unsigned int inst; +}; + +struct mcr_inst { + unsigned int opcode_1; + unsigned int opcode_2; + unsigned int cp_num; + unsigned int crn; + unsigned int crm; + unsigned int Rd; + unsigned int inst; +}; + +struct mcrr_inst { + unsigned int opcode_1; + unsigned int cp_num; + unsigned int crm; + unsigned int rt; + unsigned int rt2; +}; + +struct mrs_inst { + unsigned int R; + unsigned int Rd; +}; + +struct msr_inst { + unsigned int field_mask; + unsigned int R; + unsigned int inst; +}; + +struct pld_inst { +}; + +struct sxtb_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +}; + +struct sxtab_inst { + unsigned int Rd; + unsigned int Rn; + unsigned int Rm; + unsigned rotate; +}; + +struct sxtah_inst { + unsigned int Rd; + unsigned int Rn; + unsigned int Rm; + unsigned int rotate; +}; + +struct sxth_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +}; + +struct uxtab_inst { + unsigned int Rn; + unsigned int Rd; + unsigned int rotate; + unsigned int Rm; +}; + +struct uxtah_inst { + unsigned int Rn; + unsigned int Rd; + unsigned int rotate; + unsigned int Rm; +}; + +struct uxth_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +}; + +struct cdp_inst { + unsigned int opcode_1; + unsigned int CRn; + unsigned int CRd; + unsigned int cp_num; + unsigned int opcode_2; + unsigned int CRm; + unsigned int inst; +}; + +struct uxtb_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +}; + +struct swp_inst { + unsigned int Rn; + unsigned int Rd; + unsigned int Rm; +}; + +struct setend_inst { + unsigned int set_bigend; +}; + +struct b_2_thumb { + unsigned int imm; +}; +struct b_cond_thumb { + unsigned int imm; + unsigned int cond; +}; + +struct bl_1_thumb { + unsigned int imm; +}; +struct bl_2_thumb { + unsigned int imm; +}; +struct blx_1_thumb { + unsigned int imm; + unsigned int instr; +}; + +struct pkh_inst { + unsigned int Rm; + unsigned int Rn; + unsigned int Rd; + unsigned char imm; +}; + +// Floating point VFPv3 structures + +#define VFP_INTERPRETER_STRUCT +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_INTERPRETER_STRUCT \ No newline at end of file From 5297f5dfc914ebdfb027edb964bc141d01be9c6a Mon Sep 17 00:00:00 2001 From: archshift Date: Fri, 10 Jun 2016 18:26:42 -0700 Subject: [PATCH 14/77] arm_dyncom_interpreter: Rename anonymous enum to TransExtData --- .../arm/dyncom/arm_dyncom_interpreter.cpp | 14 +- src/core/arm/dyncom/arm_dyncom_trans.inc | 250 +++++++++--------- .../arm/dyncom/arm_dyncom_trans_struct.inc | 2 +- src/core/arm/skyeye_common/vfp/vfpinstr.cpp | 64 ++--- 4 files changed, 164 insertions(+), 166 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index b45a6cd64..0e38bef22 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -24,7 +24,7 @@ #include "core/gdbstub/gdbstub.h" -enum { +enum class TransExtData { COND = (1 << 0), NON_BRANCH = (1 << 1), DIRECT_BRANCH = (1 << 2), @@ -853,14 +853,14 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, int& bb_start, u32 addr) // Go on next, until terminal instruction // Save start addr of basicblock in CreamCache ARM_INST_PTR inst_base = nullptr; - int ret = NON_BRANCH; + TransExtData ret = TransExtData::NON_BRANCH; int size = 0; // instruction size of basic block bb_start = top; u32 phys_addr = addr; u32 pc_start = cpu->Reg[15]; - while (ret == NON_BRANCH) { + while (ret == TransExtData::NON_BRANCH) { unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base); size++; @@ -868,7 +868,7 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, int& bb_start, u32 addr) phys_addr += inst_size; if ((phys_addr & 0xfff) == 0) { - inst_base->br = END_OF_PAGE; + inst_base->br = TransExtData::END_OF_PAGE; } ret = inst_base->br; }; @@ -889,8 +889,8 @@ static int InterpreterTranslateSingle(ARMul_State* cpu, int& bb_start, u32 addr) InterpreterTranslateInstruction(cpu, phys_addr, inst_base); - if (inst_base->br == NON_BRANCH) { - inst_base->br = SINGLE_STEP; + if (inst_base->br == TransExtData::NON_BRANCH) { + inst_base->br = TransExtData::SINGLE_STEP; } cpu->instruction_cache[pc_start] = bb_start; @@ -935,7 +935,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24) #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand) - #define FETCH_INST if (inst_base->br != NON_BRANCH) goto DISPATCH; \ + #define FETCH_INST if (inst_base->br != TransExtData::NON_BRANCH) goto DISPATCH; \ inst_base = (arm_inst *)&inst_buf[ptr] #define INC_PC(l) ptr += sizeof(arm_inst) + l diff --git a/src/core/arm/dyncom/arm_dyncom_trans.inc b/src/core/arm/dyncom/arm_dyncom_trans.inc index b4bf79240..8cc5a4df8 100644 --- a/src/core/arm/dyncom/arm_dyncom_trans.inc +++ b/src/core/arm/dyncom/arm_dyncom_trans.inc @@ -7,7 +7,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -17,7 +17,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -28,7 +28,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -38,7 +38,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -49,7 +49,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -59,7 +59,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -73,12 +73,10 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; if (BIT(inst, 24)) - inst_base->br = CALL; - if (BITS(inst, 28, 31) <= 0xe) - inst_base->br |= COND; + inst_base->br = TransExtData::CALL; inst_cream->L = BIT(inst, 24); inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH; @@ -92,7 +90,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -102,7 +100,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -113,7 +111,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3); @@ -127,7 +125,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; inst_cream->inst = inst; if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { @@ -145,7 +143,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); @@ -162,7 +160,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index) { inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->CRm = BITS(inst, 0, 3); inst_cream->CRd = BITS(inst, 12, 15); @@ -180,7 +178,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index) arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -191,7 +189,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rd = BITS(inst, 12, 15); @@ -205,7 +203,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->Rn = BITS(inst, 16, 19); @@ -221,7 +219,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->Rn = BITS(inst, 16, 19); @@ -237,7 +235,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->imod0 = BIT(inst, 18); inst_cream->imod1 = BIT(inst, 19); @@ -256,7 +254,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -265,7 +263,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) { - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; } return inst_base; } @@ -276,7 +274,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -286,7 +284,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -295,7 +293,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index) arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -306,13 +304,13 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); if (BIT(inst, 15)) { - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; } return inst_base; } @@ -323,7 +321,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->Rm = BITS(inst, 0, 3); @@ -338,13 +336,13 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); if (BITS(inst, 12, 15) == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -356,13 +354,13 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); if (BITS(inst, 12, 15) == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -374,7 +372,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->rotate = BITS(inst, 10, 11); @@ -389,7 +387,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); @@ -405,7 +403,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -419,7 +417,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; if (BITS(inst, 25, 27) == 2) { @@ -439,7 +437,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -453,7 +451,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = (BITS(inst, 12, 15) == 15) ? INDIRECT_BRANCH : NON_BRANCH; // Branch if dest is R15 + inst_base->br = (BITS(inst, 12, 15) == 15) ? TransExtData::INDIRECT_BRANCH : TransExtData::NON_BRANCH; // Branch if dest is R15 inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); @@ -479,7 +477,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -493,7 +491,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -507,7 +505,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -521,7 +519,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; if (BITS(inst, 25, 27) == 2) { @@ -538,7 +536,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) } if (BITS(inst, 12, 15) == 15) { - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; } return inst_base; } @@ -548,7 +546,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index) mcr_inst *inst_cream = (mcr_inst *)inst_base->component; inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->crn = BITS(inst, 16, 19); inst_cream->crm = BITS(inst, 0, 3); @@ -567,7 +565,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->crm = BITS(inst, 0, 3); inst_cream->opcode_1 = BITS(inst, 4, 7); @@ -585,7 +583,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->S = BIT(inst, 20); inst_cream->Rn = BITS(inst, 12, 15); @@ -602,7 +600,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -611,7 +609,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) { - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; } return inst_base; } @@ -621,7 +619,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index) mrc_inst *inst_cream = (mrc_inst *)inst_base->component; inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->crn = BITS(inst, 16, 19); inst_cream->crm = BITS(inst, 0, 3); @@ -645,7 +643,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->R = BIT(inst, 22); @@ -659,7 +657,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->field_mask = BITS(inst, 16, 19); inst_cream->R = BIT(inst, 22); @@ -674,7 +672,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->S = BIT(inst, 20); inst_cream->Rm = BITS(inst, 0, 3); @@ -690,7 +688,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -699,7 +697,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) { - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; } return inst_base; @@ -711,7 +709,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -721,7 +719,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -733,7 +731,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(nop)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -745,7 +743,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->Rn = BITS(inst, 16, 19); @@ -766,7 +764,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -778,7 +776,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->op1 = BITS(inst, 21, 22); inst_cream->Rm = BITS(inst, 0, 3); @@ -807,7 +805,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rn = BITS(inst, 16, 19); @@ -845,7 +843,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rd = BITS(inst, 12, 15); @@ -870,7 +868,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) inst_base->cond = AL; inst_base->idx = index; - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -885,7 +883,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -895,7 +893,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -906,7 +904,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -916,7 +914,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -927,7 +925,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rn = BITS(inst, 16, 19); @@ -965,7 +963,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -975,7 +973,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -986,7 +984,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rn = BITS(inst, 16, 19); @@ -1004,7 +1002,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) inst_base->cond = AL; inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->set_bigend = BIT(inst, 9); @@ -1017,7 +1015,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sev)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -1029,7 +1027,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->op1 = BITS(inst, 20, 21); inst_cream->op2 = BITS(inst, 5, 7); @@ -1067,7 +1065,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->x = BIT(inst, 5); inst_cream->y = BIT(inst, 6); @@ -1086,7 +1084,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->m = BIT(inst, 5); inst_cream->Rn = BITS(inst, 0, 3); @@ -1118,7 +1116,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->S = BIT(inst, 20); inst_cream->Rm = BITS(inst, 0, 3); @@ -1136,7 +1134,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->x = BIT(inst, 5); inst_cream->y = BIT(inst, 6); @@ -1155,7 +1153,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Ra = BITS(inst, 12, 15); inst_cream->Rm = BITS(inst, 8, 11); @@ -1173,7 +1171,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 8, 11); inst_cream->Rn = BITS(inst, 0, 3); @@ -1197,7 +1195,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->m = BIT(inst, 5); inst_cream->Ra = BITS(inst, 12, 15); @@ -1225,7 +1223,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 16, 19); inst_cream->Rs = BITS(inst, 8, 11); @@ -1244,7 +1242,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->S = BIT(inst, 20); inst_cream->Rm = BITS(inst, 0, 3); @@ -1262,7 +1260,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->m = BIT(inst, 6); inst_cream->Rm = BITS(inst, 8, 11); @@ -1279,7 +1277,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) inst_base->cond = AL; inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -1294,7 +1292,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rn = BITS(inst, 0, 3); inst_cream->Rd = BITS(inst, 12, 15); @@ -1311,7 +1309,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rn = BITS(inst, 0, 3); inst_cream->Rd = BITS(inst, 12, 15); @@ -1325,7 +1323,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index) arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -1336,7 +1334,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -1349,7 +1347,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->Rm = BITS(inst, 0, 3); @@ -1364,7 +1362,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -1378,7 +1376,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->rotate = BITS(inst, 10, 11); @@ -1393,7 +1391,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->rotate = BITS(inst, 10, 11); @@ -1409,7 +1407,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -1423,7 +1421,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; @@ -1443,7 +1441,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -1457,7 +1455,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); @@ -1484,7 +1482,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; inst_cream->get_addr = get_calc_addr_op(inst); @@ -1498,7 +1496,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; if (BITS(inst, 25, 27) == 2) { @@ -1523,7 +1521,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -1533,7 +1531,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) inst_cream->shtop_func = get_shtop(inst); if (inst_cream->Rd == 15) - inst_base->br = INDIRECT_BRANCH; + inst_base->br = TransExtData::INDIRECT_BRANCH; return inst_base; } @@ -1544,7 +1542,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->num = BITS(inst, 0, 23); return inst_base; @@ -1556,7 +1554,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); @@ -1570,7 +1568,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); @@ -1584,7 +1582,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->rotate = BITS(inst, 10, 11); @@ -1601,7 +1599,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rn = BITS(inst, 16, 19); @@ -1621,7 +1619,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index) { inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rd = BITS(inst, 12, 15); inst_cream->rotate = BITS(inst, 10, 11); @@ -1638,7 +1636,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->Rn = BITS(inst, 16, 19); @@ -1654,7 +1652,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->I = BIT(inst, 25); inst_cream->S = BIT(inst, 20); @@ -1673,7 +1671,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->op1 = BITS(inst, 20, 21); inst_cream->op2 = BITS(inst, 5, 7); @@ -1711,7 +1709,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->op1 = BITS(inst, 20, 21); inst_cream->op2 = BITS(inst, 5, 7); @@ -1748,7 +1746,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 8, 11); inst_cream->Rn = BITS(inst, 0, 3); @@ -1764,7 +1762,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->S = BIT(inst, 20); inst_cream->Rm = BITS(inst, 0, 3); @@ -1781,7 +1779,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->S = BIT(inst, 20); inst_cream->Rm = BITS(inst, 0, 3); @@ -1800,7 +1798,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int ind inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } @@ -1813,7 +1811,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); inst_cream->cond = ((tinst >> 8) & 0xf); inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } @@ -1826,7 +1824,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int in inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) @@ -1837,7 +1835,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int in inst_cream->imm = (tinst & 0x07FF) << 1; inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) @@ -1849,7 +1847,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int i inst_cream->instr = tinst; inst_base->idx = index; - inst_base->br = DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } @@ -1860,7 +1858,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rn = BITS(inst, 16, 19); @@ -1897,7 +1895,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->op1 = BITS(inst, 20, 24); inst_cream->op2 = BITS(inst, 5, 7); @@ -1928,7 +1926,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->Rm = BITS(inst, 0, 3); inst_cream->Rn = BITS(inst, 16, 19); @@ -1948,7 +1946,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(wfe)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -1958,7 +1956,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(wfi)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } @@ -1968,7 +1966,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; return inst_base; } diff --git a/src/core/arm/dyncom/arm_dyncom_trans_struct.inc b/src/core/arm/dyncom/arm_dyncom_trans_struct.inc index 0a7f3ab6e..05139f00f 100644 --- a/src/core/arm/dyncom/arm_dyncom_trans_struct.inc +++ b/src/core/arm/dyncom/arm_dyncom_trans_struct.inc @@ -1,7 +1,7 @@ struct arm_inst { unsigned int idx; unsigned int cond; - int br; + TransExtData br; char component[0]; }; diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 4f9083515..1a98d0114 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -26,7 +26,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmla)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -75,7 +75,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmls)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -124,7 +124,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmla)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -174,7 +174,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmls)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -223,7 +223,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmul)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -272,7 +272,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmul)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -321,7 +321,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vadd)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -370,7 +370,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vsub)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -419,7 +419,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vdiv)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -470,7 +470,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovi)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->d = (inst_cream->single ? BITS(inst,12,15)<<1 | BIT(inst,22) : BITS(inst,12,15) | BIT(inst,22)<<4); @@ -518,7 +518,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->d = (inst_cream->single ? BITS(inst,12,15)<<1 | BIT(inst,22) : BITS(inst,12,15) | BIT(inst,22)<<4); @@ -560,7 +560,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vabs)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -610,7 +610,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vneg)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -659,7 +659,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vsqrt)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -708,7 +708,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -757,7 +757,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp2)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -806,7 +806,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbds)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -857,7 +857,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbff)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -906,7 +906,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbfi)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->dp_operation = BIT(inst, 8); inst_cream->instr = inst; @@ -962,7 +962,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrs)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->to_arm = BIT(inst, 20) == 1; inst_cream->t = BITS(inst, 12, 15); @@ -1006,7 +1006,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->reg = BITS(inst, 16, 19); inst_cream->Rt = BITS(inst, 12, 15); @@ -1069,7 +1069,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->d = BITS(inst, 16, 19)|BIT(inst, 7)<<4; inst_cream->t = BITS(inst, 12, 15); @@ -1115,7 +1115,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->reg = BITS(inst, 16, 19); inst_cream->Rt = BITS(inst, 12, 15); @@ -1200,7 +1200,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->d = BITS(inst, 16, 19)|BIT(inst, 7)<<4; inst_cream->t = BITS(inst, 12, 15); @@ -1253,7 +1253,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int inde inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->to_arm = BIT(inst, 20) == 1; inst_cream->t = BITS(inst, 12, 15); @@ -1301,7 +1301,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrd)(unsigned int inst, int index inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->to_arm = BIT(inst, 20) == 1; inst_cream->t = BITS(inst, 12, 15); @@ -1354,7 +1354,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vstr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->add = BIT(inst, 23); @@ -1420,7 +1420,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vpush)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15)<<1|BIT(inst, 22) : BITS(inst, 12, 15)|BIT(inst, 22)<<4); @@ -1495,7 +1495,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->add = BIT(inst, 23); @@ -1580,7 +1580,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vpop)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->d = (inst_cream->single ? (BITS(inst, 12, 15)<<1)|BIT(inst, 22) : BITS(inst, 12, 15)|(BIT(inst, 22)<<4)); @@ -1653,7 +1653,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vldr)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->add = BIT(inst, 23); @@ -1722,7 +1722,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = NON_BRANCH; + inst_base->br = TransExtData::NON_BRANCH; inst_cream->single = BIT(inst, 8) == 0; inst_cream->add = BIT(inst, 23); From eac4c016cb498e49a0f48803a7ea07be3caf0e1b Mon Sep 17 00:00:00 2001 From: archshift Date: Fri, 10 Jun 2016 18:42:08 -0700 Subject: [PATCH 15/77] arm_dyncom_interpreter: rename operation functions to fit style guide --- .../arm/dyncom/arm_dyncom_interpreter.cpp | 4 +- src/core/arm/dyncom/arm_dyncom_trans.inc | 64 +++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 0e38bef22..acf66b350 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -685,7 +685,7 @@ static inline void *AllocBuffer(unsigned int size) { return (void *)&inst_buf[start]; } -static shtop_fp_t get_shtop(unsigned int inst) { +static shtop_fp_t GetShifterOp(unsigned int inst) { if (BIT(inst, 25)) { return DPO(Immediate); } else if (BITS(inst, 4, 11) == 0) { @@ -710,7 +710,7 @@ static shtop_fp_t get_shtop(unsigned int inst) { return nullptr; } -static get_addr_fp_t get_calc_addr_op(unsigned int inst) { +static get_addr_fp_t GetAddressingOp(unsigned int inst) { if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) { return LnSWoUB(ImmediateOffset); } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { diff --git a/src/core/arm/dyncom/arm_dyncom_trans.inc b/src/core/arm/dyncom/arm_dyncom_trans.inc index 8cc5a4df8..70a585939 100644 --- a/src/core/arm/dyncom/arm_dyncom_trans.inc +++ b/src/core/arm/dyncom/arm_dyncom_trans.inc @@ -14,7 +14,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -35,7 +35,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -56,7 +56,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -97,7 +97,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -208,7 +208,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) inst_cream->I = BIT(inst, 25); inst_cream->Rn = BITS(inst, 16, 19); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); return inst_base; } @@ -224,7 +224,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) inst_cream->I = BIT(inst, 25); inst_cream->Rn = BITS(inst, 16, 19); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); return inst_base; } @@ -260,7 +260,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) inst_cream->S = BIT(inst, 20); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) { inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -281,7 +281,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -307,7 +307,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); if (BIT(inst, 15)) { inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -339,7 +339,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); if (BITS(inst, 12, 15) == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -357,7 +357,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); if (BITS(inst, 12, 15) == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -406,7 +406,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -440,7 +440,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -480,7 +480,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -494,7 +494,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -508,7 +508,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -606,7 +606,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) inst_cream->S = BIT(inst, 20); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) { inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -694,7 +694,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) inst_cream->S = BIT(inst, 20); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) { inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -716,7 +716,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) inst_cream->Rd = BITS(inst, 12, 15); inst_cream->Rn = BITS(inst, 16, 19); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -871,7 +871,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) inst_base->br = TransExtData::INDIRECT_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -890,7 +890,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -911,7 +911,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -970,7 +970,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -1280,7 +1280,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -1337,7 +1337,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) @@ -1365,7 +1365,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -1410,7 +1410,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -1444,7 +1444,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -1485,7 +1485,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - inst_cream->get_addr = get_calc_addr_op(inst); + inst_cream->get_addr = GetAddressingOp(inst); return inst_base; } @@ -1528,7 +1528,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); if (inst_cream->Rd == 15) inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -1641,7 +1641,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) inst_cream->I = BIT(inst, 25); inst_cream->Rn = BITS(inst, 16, 19); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); return inst_base; } @@ -1659,7 +1659,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) inst_cream->Rn = BITS(inst, 16, 19); inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); - inst_cream->shtop_func = get_shtop(inst); + inst_cream->shtop_func = GetShifterOp(inst); return inst_base; } From 765eef33197c55b524b9880c24fc9dcb8cf451fb Mon Sep 17 00:00:00 2001 From: archshift Date: Fri, 10 Jun 2016 18:45:48 -0700 Subject: [PATCH 16/77] arm_dyncom_interpreter: Add specialized GetAddressingOpLoadStoreT func This allows us to get the addressing operation for STRT, LDRT, STRBT, and LDRBT. We do this so that translation functions don't need to see the addressing ops directly. --- .../arm/dyncom/arm_dyncom_interpreter.cpp | 15 +++++++ src/core/arm/dyncom/arm_dyncom_trans.inc | 43 ++----------------- 2 files changed, 19 insertions(+), 39 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index acf66b350..7f6cf6e29 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -753,6 +753,21 @@ static get_addr_fp_t GetAddressingOp(unsigned int inst) { return nullptr; } +// Specialized for LDRT, LDRBT, STRT, and STRBT, which have specific addressing mode requirements +get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst) { + if (BITS(inst, 25, 27) == 2) { + return LnSWoUB(ImmediatePostIndexed); + } else if (BITS(inst, 25, 27) == 3) { + return LnSWoUB(ScaledRegisterPostIndexed); + } + // Reaching this would indicate the thumb version + // of this instruction, however the 3DS CPU doesn't + // support this variant (the 3DS CPU is only ARMv6K, + // while this variant is added in ARMv6T2). + // So it's sufficient for citra to not implement this. + return nullptr; +} + typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); #include "arm_dyncom_trans.inc" diff --git a/src/core/arm/dyncom/arm_dyncom_trans.inc b/src/core/arm/dyncom/arm_dyncom_trans.inc index 70a585939..48c6f81e7 100644 --- a/src/core/arm/dyncom/arm_dyncom_trans.inc +++ b/src/core/arm/dyncom/arm_dyncom_trans.inc @@ -420,13 +420,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - DEBUG_MSG; - } + inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); return inst_base; } @@ -522,18 +516,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - // Reaching this would indicate the thumb version - // of this instruction, however the 3DS CPU doesn't - // support this variant (the 3DS CPU is only ARMv6K, - // while this variant is added in ARMv6T2). - // So it's sufficient for citra to not implement this. - DEBUG_MSG; - } + inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); if (BITS(inst, 12, 15) == 15) { inst_base->br = TransExtData::INDIRECT_BRANCH; @@ -1424,14 +1407,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - DEBUG_MSG; - } + inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); return inst_base; } @@ -1499,18 +1475,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) inst_base->br = TransExtData::NON_BRANCH; inst_cream->inst = inst; - if (BITS(inst, 25, 27) == 2) { - inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); - } else if (BITS(inst, 25, 27) == 3) { - inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed); - } else { - // Reaching this would indicate the thumb version - // of this instruction, however the 3DS CPU doesn't - // support this variant (the 3DS CPU is only ARMv6K, - // while this variant is added in ARMv6T2). - // So it's sufficient for citra to not implement this. - DEBUG_MSG; - } + inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); return inst_base; } From 7b445ddff0be3e0210cb217c74cb34a16799ce0d Mon Sep 17 00:00:00 2001 From: Subv Date: Sun, 22 May 2016 12:30:13 -0500 Subject: [PATCH 17/77] Kernel/SVC: Implemented svcCreatePort. --- src/core/hle/function_wrappers.h | 10 ++++++++++ src/core/hle/kernel/client_port.h | 2 ++ src/core/hle/kernel/kernel.h | 3 ++- src/core/hle/kernel/server_port.cpp | 3 +++ src/core/hle/kernel/server_port.h | 5 ++++- src/core/hle/svc.cpp | 21 ++++++++++++++++++++- 6 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index bf7f875b6..8839ce482 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -194,6 +194,16 @@ template void Wrap() { FuncReturn(func(PARAM(0), PARAM(1)).raw); } +template void Wrap() { + Handle param_1 = 0; + Handle param_2 = 0; + u32 retval = func(¶m_1, ¶m_2, reinterpret_cast(Memory::GetPointer(PARAM(2))), PARAM(3)).raw; + // The first out parameter is moved into R2 and the second is moved into R1. + Core::g_app_core->SetReg(1, param_2); + Core::g_app_core->SetReg(2, param_1); + FuncReturn(retval); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Function wrappers that return type u32 diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index b3d15cfc5..480b6ddae 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -12,6 +12,8 @@ namespace Kernel { +class ServerPort; + class ClientPort : public Object { public: friend class ServerPort; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a53d408d4..27ba3f912 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -35,7 +35,7 @@ enum KernelHandle : Handle { enum class HandleType : u32 { Unknown = 0, - ServerPort = 1, + Session = 2, Event = 3, Mutex = 4, @@ -49,6 +49,7 @@ enum class HandleType : u32 { ResourceLimit = 12, CodeSet = 13, ClientPort = 14, + ServerPort = 15, }; enum { diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index ca41265ff..fcc684a20 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + #include "common/assert.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/thread.h" diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index e41ef8ce4..e9c972ce6 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/common_types.h" @@ -12,10 +13,12 @@ namespace Kernel { +class ClientPort; + class ServerPort final : public WaitObject { public: /** - * Creates a pair of a ServerPort and an associated ClientPort. + * Creates a pair of ServerPort and an associated ClientPort. * @param max_sessions Maximum number of sessions to the port * @param name Optional name of the ports * @return The created port tuple diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 0ce72de87..5d71d5619 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -14,12 +14,14 @@ #include "core/arm/arm_interface.h" #include "core/hle/kernel/address_arbiter.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/semaphore.h" +#include "core/hle/kernel/server_port.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -834,6 +836,23 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 return RESULT_SUCCESS; } +static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name, u32 max_sessions) { + // TODO(Subv): Implement named ports. + ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented"); + + using Kernel::ServerPort; + using Kernel::ClientPort; + using Kernel::SharedPtr; + + auto ports = ServerPort::CreatePortPair(max_sessions); + CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create(std::move(std::get>(ports)))); + // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be created. + CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create(std::move(std::get>(ports)))); + + LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions); + return RESULT_SUCCESS; +} + static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { using Kernel::MemoryRegion; @@ -1011,7 +1030,7 @@ static const FunctionDef SVC_Table[] = { {0x44, nullptr, "Unknown"}, {0x45, nullptr, "Unknown"}, {0x46, nullptr, "Unknown"}, - {0x47, nullptr, "CreatePort"}, + {0x47, HLE::Wrap, "CreatePort"}, {0x48, nullptr, "CreateSessionToPort"}, {0x49, nullptr, "CreateSession"}, {0x4A, nullptr, "AcceptSession"}, From 54b5178f6cabaac8d7dd890391d06df0990eeea2 Mon Sep 17 00:00:00 2001 From: archshift Date: Fri, 10 Jun 2016 18:50:47 -0700 Subject: [PATCH 18/77] arm_dyncom_interpreter: slightly change AllocBuffer to be intuitive --- .../arm/dyncom/arm_dyncom_interpreter.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 7f6cf6e29..68d6572aa 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -7,6 +7,7 @@ #include #include +#include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -672,19 +673,18 @@ static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst, u typedef arm_inst * ARM_INST_PTR; -#define CACHE_BUFFER_SIZE (64 * 1024 * 2000) -static char inst_buf[CACHE_BUFFER_SIZE]; -static int top = 0; -static inline void *AllocBuffer(unsigned int size) { - int start = top; - top += size; - if (top > CACHE_BUFFER_SIZE) { - LOG_ERROR(Core_ARM11, "inst_buf is full"); - CITRA_IGNORE_EXIT(-1); - } - return (void *)&inst_buf[start]; +#define TRANS_CACHE_SIZE (64 * 1024 * 2000) +static char trans_cache_buf[TRANS_CACHE_SIZE]; +static size_t trans_cache_buf_top = 0; + +static void* AllocBuffer(size_t size) { + size_t start = trans_cache_buf_top; + trans_cache_buf_top += size; + ASSERT_MSG(trans_cache_buf_top <= TRANS_CACHE_SIZE, "Translation cache is full!"); + return static_cast(&trans_cache_buf[start]); } + static shtop_fp_t GetShifterOp(unsigned int inst) { if (BIT(inst, 25)) { return DPO(Immediate); @@ -870,7 +870,7 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, int& bb_start, u32 addr) ARM_INST_PTR inst_base = nullptr; TransExtData ret = TransExtData::NON_BRANCH; int size = 0; // instruction size of basic block - bb_start = top; + bb_start = trans_cache_buf_top; u32 phys_addr = addr; u32 pc_start = cpu->Reg[15]; @@ -897,7 +897,7 @@ static int InterpreterTranslateSingle(ARMul_State* cpu, int& bb_start, u32 addr) MICROPROFILE_SCOPE(DynCom_Decode); ARM_INST_PTR inst_base = nullptr; - bb_start = top; + bb_start = trans_cache_buf_top; u32 phys_addr = addr; u32 pc_start = cpu->Reg[15]; @@ -951,7 +951,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand) #define FETCH_INST if (inst_base->br != TransExtData::NON_BRANCH) goto DISPATCH; \ - inst_base = (arm_inst *)&inst_buf[ptr] + inst_base = (arm_inst *)&trans_cache_buf[ptr] #define INC_PC(l) ptr += sizeof(arm_inst) + l #define INC_PC_STUB ptr += sizeof(arm_inst) @@ -1274,7 +1274,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { breakpoint_data = GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute); } - inst_base = (arm_inst *)&inst_buf[ptr]; + inst_base = (arm_inst *)&trans_cache_buf[ptr]; GOTO_NEXT_INST; } ADC_INST: From ca20b1f87d87bd7059c90cfe064b4da4eae33199 Mon Sep 17 00:00:00 2001 From: archshift Date: Fri, 10 Jun 2016 19:02:02 -0700 Subject: [PATCH 19/77] Make arm_dyncom_trans* into a fully fledged compilation unit --- src/core/CMakeLists.txt | 2 + .../arm/dyncom/arm_dyncom_interpreter.cpp | 48 ++----------------- ..._dyncom_trans.inc => arm_dyncom_trans.cpp} | 41 +++++++++++++--- ...om_trans_struct.inc => arm_dyncom_trans.h} | 35 +++++++++++++- 4 files changed, 73 insertions(+), 53 deletions(-) rename src/core/arm/dyncom/{arm_dyncom_trans.inc => arm_dyncom_trans.cpp} (98%) rename src/core/arm/dyncom/{arm_dyncom_trans_struct.inc => arm_dyncom_trans.h} (89%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e9b04098b..f356e4b48 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -5,6 +5,7 @@ set(SRCS arm/dyncom/arm_dyncom_dec.cpp arm/dyncom/arm_dyncom_interpreter.cpp arm/dyncom/arm_dyncom_thumb.cpp + arm/dyncom/arm_dyncom_trans.cpp arm/skyeye_common/armstate.cpp arm/skyeye_common/armsupp.cpp arm/skyeye_common/vfp/vfp.cpp @@ -140,6 +141,7 @@ set(HEADERS arm/dyncom/arm_dyncom_interpreter.h arm/dyncom/arm_dyncom_run.h arm/dyncom/arm_dyncom_thumb.h + arm/dyncom/arm_dyncom_trans.h arm/skyeye_common/arm_regformat.h arm/skyeye_common/armstate.h arm/skyeye_common/armsupp.h diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 68d6572aa..01d5d478e 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -7,7 +7,6 @@ #include #include -#include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -18,6 +17,7 @@ #include "core/arm/dyncom/arm_dyncom_dec.h" #include "core/arm/dyncom/arm_dyncom_interpreter.h" #include "core/arm/dyncom/arm_dyncom_thumb.h" +#include "core/arm/dyncom/arm_dyncom_trans.h" #include "core/arm/dyncom/arm_dyncom_run.h" #include "core/arm/skyeye_common/armstate.h" #include "core/arm/skyeye_common/armsupp.h" @@ -25,18 +25,6 @@ #include "core/gdbstub/gdbstub.h" -enum class TransExtData { - COND = (1 << 0), - NON_BRANCH = (1 << 1), - DIRECT_BRANCH = (1 << 2), - INDIRECT_BRANCH = (1 << 3), - CALL = (1 << 4), - RET = (1 << 5), - END_OF_PAGE = (1 << 6), - THUMB = (1 << 7), - SINGLE_STEP = (1 << 8) -}; - #define RM BITS(sht_oper, 0, 3) #define RS BITS(sht_oper, 8, 11) @@ -47,8 +35,6 @@ enum class TransExtData { #define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32) #define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32) -typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); - static bool CondPassed(const ARMul_State* cpu, unsigned int cond) { const bool n_flag = cpu->NFlag != 0; const bool z_flag = cpu->ZFlag != 0; @@ -246,12 +232,6 @@ static unsigned int DPO(RotateRightByRegister)(ARMul_State* cpu, unsigned int sh return shifter_operand; } -typedef void (*get_addr_fp_t)(ARMul_State *cpu, unsigned int inst, unsigned int &virt_addr); - -struct ldst_inst { - unsigned int inst; - get_addr_fp_t get_addr; -}; #define DEBUG_MSG LOG_DEBUG(Core_ARM11, "inst is %x", inst); CITRA_IGNORE_EXIT(0) #define LnSWoUB(s) glue(LnSWoUB, s) @@ -669,23 +649,7 @@ static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst, u virt_addr = addr; } -#include "arm_dyncom_trans_struct.inc" - -typedef arm_inst * ARM_INST_PTR; - -#define TRANS_CACHE_SIZE (64 * 1024 * 2000) -static char trans_cache_buf[TRANS_CACHE_SIZE]; -static size_t trans_cache_buf_top = 0; - -static void* AllocBuffer(size_t size) { - size_t start = trans_cache_buf_top; - trans_cache_buf_top += size; - ASSERT_MSG(trans_cache_buf_top <= TRANS_CACHE_SIZE, "Translation cache is full!"); - return static_cast(&trans_cache_buf[start]); -} - - -static shtop_fp_t GetShifterOp(unsigned int inst) { +shtop_fp_t GetShifterOp(unsigned int inst) { if (BIT(inst, 25)) { return DPO(Immediate); } else if (BITS(inst, 4, 11) == 0) { @@ -710,7 +674,7 @@ static shtop_fp_t GetShifterOp(unsigned int inst) { return nullptr; } -static get_addr_fp_t GetAddressingOp(unsigned int inst) { +get_addr_fp_t GetAddressingOp(unsigned int inst) { if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) { return LnSWoUB(ImmediateOffset); } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { @@ -768,10 +732,6 @@ get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst) { return nullptr; } -typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); - -#include "arm_dyncom_trans.inc" - enum { FETCH_SUCCESS, FETCH_FAILURE @@ -782,7 +742,7 @@ static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_ins ThumbDecodeStatus ret = TranslateThumbInstruction (addr, inst, arm_inst, inst_size); if (ret == ThumbDecodeStatus::BRANCH) { int inst_index; - int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); + int table_length = arm_instruction_trans_len; u32 tinstr = GetThumbInstruction(inst, addr); switch ((tinstr & 0xF800) >> 11) { diff --git a/src/core/arm/dyncom/arm_dyncom_trans.inc b/src/core/arm/dyncom/arm_dyncom_trans.cpp similarity index 98% rename from src/core/arm/dyncom/arm_dyncom_trans.inc rename to src/core/arm/dyncom/arm_dyncom_trans.cpp index 48c6f81e7..00b42c246 100644 --- a/src/core/arm/dyncom/arm_dyncom_trans.inc +++ b/src/core/arm/dyncom/arm_dyncom_trans.cpp @@ -1,5 +1,31 @@ +#include + +#include "common/assert.h" +#include "common/common_types.h" + +#include "core/arm/dyncom/arm_dyncom_interpreter.h" +#include "core/arm/dyncom/arm_dyncom_trans.h" +#include "core/arm/skyeye_common/armstate.h" +#include "core/arm/skyeye_common/armsupp.h" +#include "core/arm/skyeye_common/vfp/vfp.h" + +char trans_cache_buf[TRANS_CACHE_SIZE]; +size_t trans_cache_buf_top = 0; + +static void* AllocBuffer(size_t size) { + size_t start = trans_cache_buf_top; + trans_cache_buf_top += size; + ASSERT_MSG(trans_cache_buf_top <= TRANS_CACHE_SIZE, "Translation cache is full!"); + return static_cast(&trans_cache_buf[start]); +} + +#define glue(x, y) x ## y #define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s) +shtop_fp_t GetShifterOp(unsigned int inst); +get_addr_fp_t GetAddressingOp(unsigned int inst); +get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst); + static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) { arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst)); @@ -73,7 +99,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) inst_base->cond = BITS(inst, 28, 31); inst_base->idx = index; - inst_base->br = TransExtData::DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; if (BIT(inst, 24)) inst_base->br = TransExtData::CALL; @@ -1763,7 +1789,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int ind inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); inst_base->idx = index; - inst_base->br = TransExtData::DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } @@ -1776,7 +1802,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); inst_cream->cond = ((tinst >> 8) & 0xf); inst_base->idx = index; - inst_base->br = TransExtData::DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } @@ -1800,7 +1826,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int in inst_cream->imm = (tinst & 0x07FF) << 1; inst_base->idx = index; - inst_base->br = TransExtData::DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) @@ -1812,7 +1838,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int i inst_cream->instr = tinst; inst_base->idx = index; - inst_base->br = TransExtData::DIRECT_BRANCH; + inst_base->br = TransExtData::DIRECT_BRANCH; return inst_base; } @@ -1937,7 +1963,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) } // Floating point VFPv3 instructions - #define VFP_INTERPRETER_TRANS #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" #undef VFP_INTERPRETER_TRANS @@ -2148,4 +2173,6 @@ const transop_fp_t arm_instruction_trans[] = { INTERPRETER_TRANSLATE(bl_1_thumb), INTERPRETER_TRANSLATE(bl_2_thumb), INTERPRETER_TRANSLATE(blx_1_thumb) -}; \ No newline at end of file +}; + +const size_t arm_instruction_trans_len = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); diff --git a/src/core/arm/dyncom/arm_dyncom_trans_struct.inc b/src/core/arm/dyncom/arm_dyncom_trans.h similarity index 89% rename from src/core/arm/dyncom/arm_dyncom_trans_struct.inc rename to src/core/arm/dyncom/arm_dyncom_trans.h index 05139f00f..7af71f4e3 100644 --- a/src/core/arm/dyncom/arm_dyncom_trans_struct.inc +++ b/src/core/arm/dyncom/arm_dyncom_trans.h @@ -1,3 +1,18 @@ +struct ARMul_State; +typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); + +enum class TransExtData { + COND = (1 << 0), + NON_BRANCH = (1 << 1), + DIRECT_BRANCH = (1 << 2), + INDIRECT_BRANCH = (1 << 3), + CALL = (1 << 4), + RET = (1 << 5), + END_OF_PAGE = (1 << 6), + THUMB = (1 << 7), + SINGLE_STEP = (1 << 8) +}; + struct arm_inst { unsigned int idx; unsigned int cond; @@ -456,7 +471,23 @@ struct pkh_inst { }; // Floating point VFPv3 structures - #define VFP_INTERPRETER_STRUCT #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" -#undef VFP_INTERPRETER_STRUCT \ No newline at end of file +#undef VFP_INTERPRETER_STRUCT + +typedef void (*get_addr_fp_t)(ARMul_State *cpu, unsigned int inst, unsigned int &virt_addr); + +struct ldst_inst { + unsigned int inst; + get_addr_fp_t get_addr; +}; + +typedef arm_inst* ARM_INST_PTR; +typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); + +extern const transop_fp_t arm_instruction_trans[]; +extern const size_t arm_instruction_trans_len; + +#define TRANS_CACHE_SIZE (64 * 1024 * 2000) +extern char trans_cache_buf[TRANS_CACHE_SIZE]; +extern size_t trans_cache_buf_top; From 914eb7561e216d04b9e1f24298f91b6f035abd92 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Tue, 14 Jun 2016 18:36:57 -0700 Subject: [PATCH 20/77] Fix AppVeyor WinSCP download --- appveyor.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fa4134384..55beb7820 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -44,12 +44,10 @@ on_success: # Do a second archive with only the binaries 7z a $BUILD_NAME_NOQT .\build\bin\release\*.exe - # Download winscp - Invoke-WebRequest "http://iweb.dl.sourceforge.net/project/winscp/WinSCP/5.7.3/winscp573.zip" -OutFile "winscp573.zip" - 7z e -y winscp573.zip - # Upload to server - .\WinSCP.com /command ` + # Download WinSCP and upload to server + choco install winscp.portable + WinSCP.exe /command ` "option batch abort" ` "option confirm off" ` "open sftp://citra-builds:${env:BUILD_PASSWORD}@builds.citra-emu.org -hostkey=*" ` From c283a8509d3edf79a6c8eaf3d709b41d545036b5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 17 Jun 2016 09:03:30 -0400 Subject: [PATCH 21/77] travis: Use Qt 5 on Ubuntu CI builds --- .travis-build.sh | 2 +- .travis.yml | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.travis-build.sh b/.travis-build.sh index 511df04ac..9e9c59b7d 100755 --- a/.travis-build.sh +++ b/.travis-build.sh @@ -16,7 +16,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH mkdir build && cd build - cmake -DCITRA_FORCE_QT4=ON .. + cmake .. make -j4 ctest -VV -C Release diff --git a/.travis.yml b/.travis.yml index 8d86baece..06c00a162 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,17 @@ -os: - - linux - - osx - language: cpp +matrix: + include: + - os: linux + sudo: true + dist: trusty + - os: osx + sudo: false + env: global: - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg=" -sudo: false - addons: apt: sources: @@ -17,6 +19,8 @@ addons: packages: - gcc-5 - g++-5 + - qt5-default + - libqt5opengl5-dev - xorg-dev - lib32stdc++6 # For CMake - lftp # To upload builds From a81b9ca6894e5117f48831aa23d2a028bbb29719 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 17 Jun 2016 09:10:34 -0400 Subject: [PATCH 22/77] travis: Use GCC 6 on Ubuntu CI builds --- .travis-build.sh | 4 ++-- .travis-deps.sh | 4 ++-- .travis.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis-build.sh b/.travis-build.sh index 9e9c59b7d..8440b4f5c 100755 --- a/.travis-build.sh +++ b/.travis-build.sh @@ -11,8 +11,8 @@ fi #if OS is linux or is not set if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then - export CC=gcc-5 - export CXX=g++-5 + export CC=gcc-6 + export CXX=g++-6 export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH mkdir build && cd build diff --git a/.travis-deps.sh b/.travis-deps.sh index 4a79feb70..10b69f5c4 100755 --- a/.travis-deps.sh +++ b/.travis-deps.sh @@ -5,8 +5,8 @@ set -x #if OS is linux or is not set if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then - export CC=gcc-5 - export CXX=g++-5 + export CC=gcc-6 + export CXX=g++-6 mkdir -p $HOME/.local curl -L http://www.cmake.org/files/v3.1/cmake-3.1.0-Linux-i386.tar.gz \ diff --git a/.travis.yml b/.travis.yml index 06c00a162..8be395770 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,8 +17,8 @@ addons: sources: - ubuntu-toolchain-r-test packages: - - gcc-5 - - g++-5 + - gcc-6 + - g++-6 - qt5-default - libqt5opengl5-dev - xorg-dev From d5f5aeeab8ea030f92ad9e30a042a90c8c2762b0 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 17 Jun 2016 09:16:12 -0400 Subject: [PATCH 23/77] CMakeLists: Drop support for Qt 4 --- CMakeLists.txt | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7b0af115..9a436b981 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,6 @@ option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF) option(ENABLE_QT "Enable the Qt frontend" ON) option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF) -option(CITRA_FORCE_QT4 "Use Qt4 even if Qt5 is available." OFF) if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/pre-commit) message(STATUS "Copying pre-commit hook") @@ -201,16 +200,8 @@ if (ENABLE_QT) set(QT_PREFIX_HINT) endif() - if (NOT CITRA_FORCE_QT4) - find_package(Qt5 COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT}) - set(CITRA_QT_LIBS Qt5::Widgets Qt5::OpenGL) - endif() - - if (CITRA_FORCE_QT4 OR NOT Qt5_FOUND) - # Try to fallback to Qt4 - find_package(Qt4 REQUIRED COMPONENTS QtGui QtOpenGL ${QT_PREFIX_HINT}) - set(CITRA_QT_LIBS Qt4::QtGui Qt4::QtOpenGL) - endif() + find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT}) + set(CITRA_QT_LIBS Qt5::Widgets Qt5::OpenGL) endif() # This function should be passed a list of all files in a target. It will automatically generate From c52754e79a46a9781af418cc6955b4c3ab5dfa5e Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sat, 18 Jun 2016 23:37:09 -0700 Subject: [PATCH 24/77] Qt: Fix MicroProfile dpi scaling --- src/citra_qt/debugger/profiler.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp index 585ac049a..17898f54b 100644 --- a/src/citra_qt/debugger/profiler.cpp +++ b/src/citra_qt/debugger/profiler.cpp @@ -151,8 +151,8 @@ private: /// This timer is used to redraw the widget's contents continuously. To save resources, it only /// runs while the widget is visible. QTimer update_timer; - /// Scale the coordinate system appropriately when physical DPI != logical DPI. - qreal x_scale, y_scale; + /// Scale the coordinate system appropriately when dpi != 96. + qreal x_scale = 1.0, y_scale = 1.0; }; #endif @@ -222,15 +222,14 @@ MicroProfileWidget::MicroProfileWidget(QWidget* parent) : QWidget(parent) { MicroProfileInitUI(); connect(&update_timer, SIGNAL(timeout()), SLOT(update())); - - QPainter painter(this); - x_scale = qreal(painter.device()->physicalDpiX()) / qreal(painter.device()->logicalDpiX()); - y_scale = qreal(painter.device()->physicalDpiY()) / qreal(painter.device()->logicalDpiY()); } void MicroProfileWidget::paintEvent(QPaintEvent* ev) { QPainter painter(this); + // The units used by Microprofile for drawing are based in pixels on a 96 dpi display. + x_scale = qreal(painter.device()->logicalDpiX()) / 96.0; + y_scale = qreal(painter.device()->logicalDpiY()) / 96.0; painter.scale(x_scale, y_scale); painter.setBackground(Qt::black); @@ -241,7 +240,7 @@ void MicroProfileWidget::paintEvent(QPaintEvent* ev) { painter.setFont(font); mp_painter = &painter; - MicroProfileDraw(rect().width(), rect().height()); + MicroProfileDraw(rect().width() / x_scale, rect().height() / y_scale); mp_painter = nullptr; } From d6792632f0a426247167fc91c12c1f640748464f Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 19 Jun 2016 00:09:16 -0700 Subject: [PATCH 25/77] Fix recursive scanning of directories ForeachDirectoryEntry didn't actually do anything with the `recursive` parameter, and the corresponding callback parameter was shadowing the actual recursion counters in the user functions. --- src/citra_qt/game_list.cpp | 8 +++----- src/common/file_util.cpp | 22 ++++++++++------------ src/common/file_util.h | 7 ++----- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index 15484fae3..1910da3ac 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -120,11 +120,9 @@ void GameList::LoadInterfaceLayout() void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { - const auto callback = [&](unsigned* num_entries_out, - const std::string& directory, - const std::string& virtual_name, - unsigned int recursion) -> bool { - + const auto callback = [this, recursion](unsigned* num_entries_out, + const std::string& directory, + const std::string& virtual_name) -> bool { std::string physical_name = directory + DIR_SEP + virtual_name; if (stop_processing) diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 17af7c385..84fe95c8c 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -434,7 +434,7 @@ bool CreateEmptyFile(const std::string &filename) } -bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback, unsigned int recursion) +bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback) { LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str()); @@ -472,7 +472,7 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo continue; unsigned ret_entries = 0; - if (!callback(&ret_entries, directory, virtual_name, recursion)) { + if (!callback(&ret_entries, directory, virtual_name)) { callback_error = true; break; } @@ -497,10 +497,9 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion) { - const auto callback = [&parent_entry](unsigned* num_entries_out, - const std::string& directory, - const std::string& virtual_name, - unsigned int recursion) -> bool { + const auto callback = [recursion, &parent_entry](unsigned* num_entries_out, + const std::string& directory, + const std::string& virtual_name) -> bool { FSTEntry entry; entry.virtualName = virtual_name; entry.physicalName = directory + DIR_SEP + virtual_name; @@ -526,16 +525,15 @@ unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, }; unsigned num_entries; - return ForeachDirectoryEntry(&num_entries, directory, callback, recursion) ? num_entries : 0; + return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0; } bool DeleteDirRecursively(const std::string &directory, unsigned int recursion) { - const static auto callback = [](unsigned* num_entries_out, - const std::string& directory, - const std::string& virtual_name, - unsigned int recursion) -> bool { + const auto callback = [recursion](unsigned* num_entries_out, + const std::string& directory, + const std::string& virtual_name) -> bool { std::string new_path = directory + DIR_SEP_CHR + virtual_name; if (IsDirectory(new_path)) { @@ -546,7 +544,7 @@ bool DeleteDirRecursively(const std::string &directory, unsigned int recursion) return Delete(new_path); }; - if (!ForeachDirectoryEntry(nullptr, directory, callback, recursion)) + if (!ForeachDirectoryEntry(nullptr, directory, callback)) return false; // Delete the outermost directory diff --git a/src/common/file_util.h b/src/common/file_util.h index 32ae2dc57..7ad7ee829 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -105,13 +105,11 @@ bool CreateEmptyFile(const std::string &filename); * @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null * @param directory the path to the enclosing directory * @param virtual_name the entry name, without any preceding directory info - * @param recursion Number of children directory to read before giving up * @return whether handling the entry succeeded */ using DirectoryEntryCallable = std::function; + const std::string& virtual_name)>; /** * Scans a directory, calling the callback for each file/directory contained within. @@ -119,10 +117,9 @@ using DirectoryEntryCallable = std::function Date: Tue, 21 Jun 2016 14:19:46 +0200 Subject: [PATCH 26/77] Add GPL license.txt and README.md to builds --- .travis-upload.sh | 4 ++++ README.md | 2 ++ appveyor.yml | 8 ++++---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.travis-upload.sh b/.travis-upload.sh index d86775cb9..1ad8f5e5e 100755 --- a/.travis-upload.sh +++ b/.travis-upload.sh @@ -25,6 +25,10 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then dylibbundler -b -x "${REV_NAME}/citra" -cd -d "${REV_NAME}/libs" -p "@executable_path/libs/" fi + # Copy documentation + cp license.txt "$REV_NAME" + cp README.md "$REV_NAME" + ARCHIVE_NAME="${REV_NAME}.tar.xz" tar -cJvf "$ARCHIVE_NAME" "$REV_NAME" lftp -c "open -u citra-builds,$BUILD_PASSWORD sftp://builds.citra-emu.org; set sftp:auto-confirm yes; put -O '$UPLOAD_DIR' '$ARCHIVE_NAME'" diff --git a/README.md b/README.md index a27acbc15..5463763ad 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ For development discussion, please join us @ #citra on freenode. ### Development +Most of the development happens on GitHub. It's also where [our central repository](https://github.com/citra-emu/citra) is hosted. + If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md), [TODO list](https://docs.google.com/document/d/1SWIop0uBI9IW8VGg97TAtoT_CHNoP42FzYmvG1F4QDA) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information). You should as well contact any of the developers in the forum in order to know about the current state of the emulator. ### Building diff --git a/appveyor.yml b/appveyor.yml index 55beb7820..e82bdf0cf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -39,10 +39,10 @@ on_success: # Where are these spaces coming from? Regardless, let's remove them $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" $BUILD_NAME_NOQT = "citra-noqt-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" - # Zip up the build folder - 7z a $BUILD_NAME .\build\bin\release\* - # Do a second archive with only the binaries - 7z a $BUILD_NAME_NOQT .\build\bin\release\*.exe + # Zip up the build folder and documentation + 7z a $BUILD_NAME .\build\bin\release\* .\license.txt .\README.md + # Do a second archive with only the binaries (excludes dlls) and documentation + 7z a $BUILD_NAME_NOQT .\build\bin\release\*.exe .\license.txt .\README.md # Download WinSCP and upload to server From 0f9274fe2426e3b454d93f07e849243d51991cf8 Mon Sep 17 00:00:00 2001 From: scurest Date: Sat, 25 Jun 2016 13:26:21 -0500 Subject: [PATCH 27/77] Remove superfluous std::move in return std::move(local_var) --- src/common/logging/backend.cpp | 2 +- src/video_core/debug_utils/debug_utils.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index d7008fc66..0b2fabec9 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -117,7 +117,7 @@ Entry CreateEntry(Class log_class, Level log_level, vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args); entry.message = std::string(formatting_buffer.data()); - return std::move(entry); + return entry; } static Filter* filter = nullptr; diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 871368323..bfa686380 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -328,7 +328,7 @@ std::unique_ptr FinishPicaTracing() std::lock_guard lock(pica_trace_mutex); std::unique_ptr ret(std::move(pica_trace)); - return std::move(ret); + return ret; } const Math::Vec4 LookupTexture(const u8* source, int x, int y, const TextureInfo& info, bool disable_alpha) { From f9be06b15f08cb559580e1d19b43158640a37d67 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 2 Dec 2015 13:23:51 -0500 Subject: [PATCH 28/77] PICA: Implement scissor test --- src/video_core/pica.h | 32 ++++++++++++++++++- src/video_core/rasterizer.cpp | 22 ++++++++++++- .../renderer_opengl/gl_rasterizer.cpp | 26 +++++++++++++++ .../renderer_opengl/gl_rasterizer.h | 12 ++++++- .../renderer_opengl/gl_shader_gen.cpp | 16 ++++++++++ 5 files changed, 105 insertions(+), 3 deletions(-) diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 09702d46a..065a3fd0c 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -115,7 +115,36 @@ struct Regs { BitField<24, 5, Semantic> map_w; } vs_output_attributes[7]; - INSERT_PADDING_WORDS(0x11); + INSERT_PADDING_WORDS(0xe); + + enum class ScissorMode : u32 { + Disabled = 0, + Exclude = 1, // Exclude pixels inside the scissor box + + Include = 3 // Exclude pixels outside the scissor box + }; + + struct { + BitField<0, 2, ScissorMode> mode; + + union { + BitField< 0, 16, u32> right; + BitField<16, 16, u32> bottom; + }; + + union { + BitField< 0, 16, u32> left_minus_1; + BitField<16, 16, u32> top_minus_1; + }; + + u32 GetTop() const { + return top_minus_1 + 1; + } + + u32 GetLeft() const { + return left_minus_1 + 1; + } + } scissor_test; union { BitField< 0, 10, s32> x; @@ -1328,6 +1357,7 @@ ASSERT_REG_POSITION(viewport_depth_range, 0x4d); ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e); ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); +ASSERT_REG_POSITION(scissor_test, 0x65); ASSERT_REG_POSITION(viewport_corner, 0x68); ASSERT_REG_POSITION(depthmap_enable, 0x6D); ASSERT_REG_POSITION(texture0_enable, 0x80); diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index a84170094..514d64208 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -338,12 +338,25 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, return; } - // TODO: Proper scissor rect test! u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); u16 max_x = std::max({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); + // Convert the scissor box coordinates to 12.4 fixed point + u16 scissor_left = (u16)(regs.scissor_test.GetLeft() << 4); + u16 scissor_top = (u16)(regs.scissor_test.GetTop() << 4); + u16 scissor_right = (u16)(regs.scissor_test.right << 4); + u16 scissor_bottom = (u16)(regs.scissor_test.bottom << 4); + + if (regs.scissor_test.mode == Regs::ScissorMode::Include) { + // Calculate the new bounds + min_x = std::max(min_x, scissor_right); + min_y = std::max(min_y, scissor_bottom); + max_x = std::min(max_x, scissor_left); + max_y = std::min(max_y, scissor_top); + } + min_x &= Fix12P4::IntMask(); min_y &= Fix12P4::IntMask(); max_x = ((max_x + Fix12P4::FracMask()) & Fix12P4::IntMask()); @@ -383,6 +396,13 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, for (u16 y = min_y + 8; y < max_y; y += 0x10) { for (u16 x = min_x + 8; x < max_x; x += 0x10) { + // Do not process the pixel if it's inside the scissor box and the scissor mode is set to Exclude + if (regs.scissor_test.mode == Regs::ScissorMode::Exclude && + x >= scissor_right && x <= scissor_left && + y >= scissor_bottom && y <= scissor_top) { + continue; + } + // Calculate the barycentric coordinates w0, w1 and w2 int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y}); int w1 = bias1 + SignedArea(vtxpos[2].xy(), vtxpos[0].xy(), {x, y}); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 328a4f66b..14ee97d57 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -353,6 +353,15 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { SyncColorWriteMask(); break; + // Scissor test + case PICA_REG_INDEX(scissor_test.mode): + shader_dirty = true; + break; + case PICA_REG_INDEX(scissor_test.right): + case PICA_REG_INDEX(scissor_test.left_minus_1): + SyncScissorTest(); + break; + // Logic op case PICA_REG_INDEX(output_merger.logic_op): SyncLogicOp(); @@ -1002,6 +1011,7 @@ void RasterizerOpenGL::SetShader() { SyncDepthOffset(); SyncAlphaTest(); SyncCombinerColor(); + SyncScissorTest(); auto& tev_stages = Pica::g_state.regs.GetTevStages(); for (int index = 0; index < tev_stages.size(); ++index) SyncTevConstColor(index, tev_stages[index]); @@ -1166,6 +1176,22 @@ void RasterizerOpenGL::SyncDepthTest() { PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS; } +void RasterizerOpenGL::SyncScissorTest() { + const auto& regs = Pica::g_state.regs; + + if (uniform_block_data.data.scissor_right != regs.scissor_test.right || + uniform_block_data.data.scissor_bottom != regs.scissor_test.bottom || + uniform_block_data.data.scissor_left != regs.scissor_test.GetLeft() || + uniform_block_data.data.scissor_top != regs.scissor_test.GetTop()) { + + uniform_block_data.data.scissor_right = regs.scissor_test.right; + uniform_block_data.data.scissor_bottom = regs.scissor_test.bottom; + uniform_block_data.data.scissor_left = regs.scissor_test.GetLeft(); + uniform_block_data.data.scissor_top = regs.scissor_test.GetTop(); + uniform_block_data.dirty = true; + } +} + void RasterizerOpenGL::SyncCombinerColor() { auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 42482df4b..193c10291 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -56,6 +56,8 @@ union PicaShaderConfig { const auto& regs = Pica::g_state.regs; + state.scissor_test_mode = regs.scissor_test.mode; + state.depthmap_enable = regs.depthmap_enable; state.alpha_test_func = regs.output_merger.alpha_test.enable ? @@ -172,6 +174,7 @@ union PicaShaderConfig { struct State { Pica::Regs::CompareFunc alpha_test_func; + Pica::Regs::ScissorMode scissor_test_mode; Pica::Regs::TextureConfig::TextureType texture0_type; std::array tev_stages; u8 combiner_buffer_input; @@ -328,6 +331,10 @@ private: GLint alphatest_ref; GLfloat depth_scale; GLfloat depth_offset; + GLint scissor_right; + GLint scissor_bottom; + GLint scissor_left; + GLint scissor_top; alignas(16) GLvec3 fog_color; alignas(16) GLvec3 lighting_global_ambient; LightSrc light_src[8]; @@ -335,7 +342,7 @@ private: alignas(16) GLvec4 tev_combiner_buffer_color; }; - static_assert(sizeof(UniformData) == 0x3A0, "The size of the UniformData structure has changed, update the structure in the shader"); + static_assert(sizeof(UniformData) == 0x3B0, "The size of the UniformData structure has changed, update the structure in the shader"); static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); /// Sets the OpenGL shader in accordance with the current PICA register state @@ -384,6 +391,9 @@ private: /// Syncs the depth test states to match the PICA register void SyncDepthTest(); + /// Syncs the scissor test state to match the PICA register + void SyncScissorTest(); + /// Syncs the TEV combiner color buffer to match the PICA register void SyncCombinerColor(); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 3bace7f01..10bb44210 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -539,6 +539,8 @@ in float texcoord0_w; in vec4 normquat; in vec3 view; +in vec4 gl_FragCoord; + out vec4 color; struct LightSrc { @@ -555,6 +557,10 @@ layout (std140) uniform shader_data { int alphatest_ref; float depth_scale; float depth_offset; + int scissor_right; + int scissor_bottom; + int scissor_left; + int scissor_top; vec3 fog_color; vec3 lighting_global_ambient; LightSrc light_src[NUM_LIGHTS]; @@ -582,6 +588,16 @@ vec4 secondary_fragment_color = vec4(0.0); return out; } + // Append the scissor test + if (state.scissor_test_mode == Regs::ScissorMode::Include || state.scissor_test_mode == Regs::ScissorMode::Exclude) { + out += "if (scissor_left <= scissor_right || scissor_top <= scissor_bottom) discard;\n"; + out += "if ("; + // Negate the condition if we have to keep only the pixels outside the scissor box + if (state.scissor_test_mode == Regs::ScissorMode::Include) + out += "!"; + out += "(gl_FragCoord.x >= scissor_right && gl_FragCoord.x <= scissor_left && gl_FragCoord.y >= scissor_bottom && gl_FragCoord.y <= scissor_top)) discard;\n"; + } + out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; out += "float depth = z_over_w * depth_scale + depth_offset;\n"; if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { From f0b9bc14b64765bd8bc78cb4cfb4a30eb9ab9324 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 24 Jan 2016 22:59:16 -0800 Subject: [PATCH 29/77] PICA: Scissor fixes and cleanups --- src/video_core/pica.h | 16 +++--------- src/video_core/rasterizer.cpp | 25 ++++++++++--------- .../renderer_opengl/gl_rasterizer.cpp | 20 +++++++-------- .../renderer_opengl/gl_rasterizer.h | 8 +++--- .../renderer_opengl/gl_shader_gen.cpp | 15 +++++------ 5 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 065a3fd0c..7099c31a0 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -128,22 +128,14 @@ struct Regs { BitField<0, 2, ScissorMode> mode; union { - BitField< 0, 16, u32> right; - BitField<16, 16, u32> bottom; + BitField< 0, 16, u32> x1; + BitField<16, 16, u32> y1; }; union { - BitField< 0, 16, u32> left_minus_1; - BitField<16, 16, u32> top_minus_1; + BitField< 0, 16, u32> x2; + BitField<16, 16, u32> y2; }; - - u32 GetTop() const { - return top_minus_1 + 1; - } - - u32 GetLeft() const { - return left_minus_1 + 1; - } } scissor_test; union { diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 514d64208..6f369a00e 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -344,17 +344,18 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); // Convert the scissor box coordinates to 12.4 fixed point - u16 scissor_left = (u16)(regs.scissor_test.GetLeft() << 4); - u16 scissor_top = (u16)(regs.scissor_test.GetTop() << 4); - u16 scissor_right = (u16)(regs.scissor_test.right << 4); - u16 scissor_bottom = (u16)(regs.scissor_test.bottom << 4); + u16 scissor_x1 = (u16)( regs.scissor_test.x1 << 4); + u16 scissor_y1 = (u16)( regs.scissor_test.y1 << 4); + // x2,y2 have +1 added to cover the entire sub-pixel area + u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4); + u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4); if (regs.scissor_test.mode == Regs::ScissorMode::Include) { // Calculate the new bounds - min_x = std::max(min_x, scissor_right); - min_y = std::max(min_y, scissor_bottom); - max_x = std::min(max_x, scissor_left); - max_y = std::min(max_y, scissor_top); + min_x = std::max(min_x, scissor_x1); + min_y = std::max(min_y, scissor_y1); + max_x = std::min(max_x, scissor_x2); + max_y = std::min(max_y, scissor_y2); } min_x &= Fix12P4::IntMask(); @@ -397,10 +398,10 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, for (u16 x = min_x + 8; x < max_x; x += 0x10) { // Do not process the pixel if it's inside the scissor box and the scissor mode is set to Exclude - if (regs.scissor_test.mode == Regs::ScissorMode::Exclude && - x >= scissor_right && x <= scissor_left && - y >= scissor_bottom && y <= scissor_top) { - continue; + if (regs.scissor_test.mode == Regs::ScissorMode::Exclude) { + if (x >= scissor_x1 && x < scissor_x2 && + y >= scissor_y1 && y < scissor_y2) + continue; } // Calculate the barycentric coordinates w0, w1 and w2 diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 14ee97d57..ab02aadc9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -357,8 +357,8 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { case PICA_REG_INDEX(scissor_test.mode): shader_dirty = true; break; - case PICA_REG_INDEX(scissor_test.right): - case PICA_REG_INDEX(scissor_test.left_minus_1): + case PICA_REG_INDEX(scissor_test.x1): // and y1 + case PICA_REG_INDEX(scissor_test.x2): // and y2 SyncScissorTest(); break; @@ -1179,15 +1179,15 @@ void RasterizerOpenGL::SyncDepthTest() { void RasterizerOpenGL::SyncScissorTest() { const auto& regs = Pica::g_state.regs; - if (uniform_block_data.data.scissor_right != regs.scissor_test.right || - uniform_block_data.data.scissor_bottom != regs.scissor_test.bottom || - uniform_block_data.data.scissor_left != regs.scissor_test.GetLeft() || - uniform_block_data.data.scissor_top != regs.scissor_test.GetTop()) { + if (uniform_block_data.data.scissor_x1 != regs.scissor_test.x1 || + uniform_block_data.data.scissor_y1 != regs.scissor_test.y1 || + uniform_block_data.data.scissor_x2 != regs.scissor_test.x2 || + uniform_block_data.data.scissor_y2 != regs.scissor_test.y2) { - uniform_block_data.data.scissor_right = regs.scissor_test.right; - uniform_block_data.data.scissor_bottom = regs.scissor_test.bottom; - uniform_block_data.data.scissor_left = regs.scissor_test.GetLeft(); - uniform_block_data.data.scissor_top = regs.scissor_test.GetTop(); + uniform_block_data.data.scissor_x1 = regs.scissor_test.x1; + uniform_block_data.data.scissor_y1 = regs.scissor_test.y1; + uniform_block_data.data.scissor_x2 = regs.scissor_test.x2; + uniform_block_data.data.scissor_y2 = regs.scissor_test.y2; uniform_block_data.dirty = true; } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 193c10291..653ac9cd9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -331,10 +331,10 @@ private: GLint alphatest_ref; GLfloat depth_scale; GLfloat depth_offset; - GLint scissor_right; - GLint scissor_bottom; - GLint scissor_left; - GLint scissor_top; + GLint scissor_x1; + GLint scissor_y1; + GLint scissor_x2; + GLint scissor_y2; alignas(16) GLvec3 fog_color; alignas(16) GLvec3 lighting_global_ambient; LightSrc light_src[8]; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 10bb44210..b2e452afe 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -557,10 +557,10 @@ layout (std140) uniform shader_data { int alphatest_ref; float depth_scale; float depth_offset; - int scissor_right; - int scissor_bottom; - int scissor_left; - int scissor_top; + int scissor_x1; + int scissor_y1; + int scissor_x2; + int scissor_y2; vec3 fog_color; vec3 lighting_global_ambient; LightSrc light_src[NUM_LIGHTS]; @@ -589,13 +589,14 @@ vec4 secondary_fragment_color = vec4(0.0); } // Append the scissor test - if (state.scissor_test_mode == Regs::ScissorMode::Include || state.scissor_test_mode == Regs::ScissorMode::Exclude) { - out += "if (scissor_left <= scissor_right || scissor_top <= scissor_bottom) discard;\n"; + if (state.scissor_test_mode != Regs::ScissorMode::Disabled) { out += "if ("; // Negate the condition if we have to keep only the pixels outside the scissor box if (state.scissor_test_mode == Regs::ScissorMode::Include) out += "!"; - out += "(gl_FragCoord.x >= scissor_right && gl_FragCoord.x <= scissor_left && gl_FragCoord.y >= scissor_bottom && gl_FragCoord.y <= scissor_top)) discard;\n"; + // x2,y2 have +1 added to cover the entire pixel area + out += "(gl_FragCoord.x >= scissor_x1 && gl_FragCoord.x < scissor_x2 + 1 && " + "gl_FragCoord.y >= scissor_y1 && gl_FragCoord.y < scissor_y2 + 1)) discard;\n"; } out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; From ecf6ecf32537634db15946630d62ac3bdc4fe8c9 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 27 Jun 2016 22:16:04 -0700 Subject: [PATCH 30/77] OpenGL: Add scaled resolution support to scissor --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 8 ++++++++ src/video_core/renderer_opengl/gl_rasterizer.h | 3 ++- src/video_core/renderer_opengl/gl_shader_gen.cpp | 7 +++++-- src/video_core/renderer_opengl/pica_to_gl.h | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index ab02aadc9..f8393c618 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -196,6 +196,14 @@ void RasterizerOpenGL::DrawTriangles() { (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), (GLsizei)(viewport_width * color_surface->res_scale_width), (GLsizei)(viewport_height * color_surface->res_scale_height)); + if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || + uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { + + uniform_block_data.data.framebuffer_scale[0] = color_surface->res_scale_width; + uniform_block_data.data.framebuffer_scale[1] = color_surface->res_scale_height; + uniform_block_data.dirty = true; + } + // Sync and bind the texture surfaces const auto pica_textures = regs.GetTextures(); for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 653ac9cd9..c5029432b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -328,6 +328,7 @@ private: // the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. // Not following that rule will cause problems on some AMD drivers. struct UniformData { + alignas(8) GLvec2 framebuffer_scale; GLint alphatest_ref; GLfloat depth_scale; GLfloat depth_offset; @@ -342,7 +343,7 @@ private: alignas(16) GLvec4 tev_combiner_buffer_color; }; - static_assert(sizeof(UniformData) == 0x3B0, "The size of the UniformData structure has changed, update the structure in the shader"); + static_assert(sizeof(UniformData) == 0x3C0, "The size of the UniformData structure has changed, update the structure in the shader"); static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); /// Sets the OpenGL shader in accordance with the current PICA register state diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index b2e452afe..36513dedc 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -554,6 +554,7 @@ struct LightSrc { }; layout (std140) uniform shader_data { + vec2 framebuffer_scale; int alphatest_ref; float depth_scale; float depth_offset; @@ -595,8 +596,10 @@ vec4 secondary_fragment_color = vec4(0.0); if (state.scissor_test_mode == Regs::ScissorMode::Include) out += "!"; // x2,y2 have +1 added to cover the entire pixel area - out += "(gl_FragCoord.x >= scissor_x1 && gl_FragCoord.x < scissor_x2 + 1 && " - "gl_FragCoord.y >= scissor_y1 && gl_FragCoord.y < scissor_y2 + 1)) discard;\n"; + out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && " + "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " + "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " + "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; } out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h index 6dc2758c5..d9b9c9cc2 100644 --- a/src/video_core/renderer_opengl/pica_to_gl.h +++ b/src/video_core/renderer_opengl/pica_to_gl.h @@ -17,6 +17,7 @@ #include "video_core/pica.h" +using GLvec2 = std::array; using GLvec3 = std::array; using GLvec4 = std::array; From e023a4cfd033c9c82bf2821b51a2e83930b6048d Mon Sep 17 00:00:00 2001 From: wwylele Date: Thu, 30 Jun 2016 11:26:53 +0300 Subject: [PATCH 31/77] Result: fix and update ErrorModule --- src/core/hle/result.h | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 57dedcb22..68d6f5a87 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -135,15 +135,28 @@ enum class ErrorModule : u32 { MCU = 72, NS = 73, News = 74, - RO_1 = 75, + RO = 75, GD = 76, CardSPI = 77, EC = 78, - RO_2 = 79, - WebBrowser = 80, - Test = 81, - ENC = 82, - PIA = 83, + WebBrowser = 79, + Test = 80, + ENC = 81, + PIA = 82, + ACT = 83, + VCTL = 84, + OLV = 85, + NEIA = 86, + NPNS = 87, + + AVD = 90, + L2B = 91, + MVD = 92, + NFC = 93, + UART = 94, + SPM = 95, + QTM = 96, + NFP = 97, Application = 254, InvalidResult = 255 From 3687a805ecbe870e231234fec77b82408388d4ac Mon Sep 17 00:00:00 2001 From: wwylele Date: Tue, 7 Jun 2016 18:27:14 +0300 Subject: [PATCH 32/77] Service::CFG: name sound output modes --- src/core/hle/service/cfg/cfg.cpp | 3 +-- src/core/hle/service/cfg/cfg.h | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index e067db645..8e0848bf1 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -73,8 +73,7 @@ static const ConsoleModelInfo CONSOLE_MODEL = { NINTENDO_3DS_XL, { 0, 0, 0 } }; static const u8 CONSOLE_LANGUAGE = LANGUAGE_EN; static const UsernameBlock CONSOLE_USERNAME_BLOCK = { u"CITRA", 0, 0 }; static const BirthdayBlock PROFILE_BIRTHDAY = { 3, 25 }; // March 25th, 2014 -/// TODO(Subv): Find out what this actually is -static const u8 SOUND_OUTPUT_MODE = 2; +static const u8 SOUND_OUTPUT_MODE = SOUND_SURROUND; static const u8 UNITED_STATES_COUNTRY_ID = 49; /// TODO(Subv): Find what the other bytes are static const ConsoleCountryInfo COUNTRY_INFO = { { 0, 0, 0 }, UNITED_STATES_COUNTRY_ID }; diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index c01806836..57e0821f3 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h @@ -38,6 +38,12 @@ enum SystemLanguage { LANGUAGE_RU = 10 }; +enum SoundOutputMode { + SOUND_MONO = 0, + SOUND_STEREO = 1, + SOUND_SURROUND = 2 +}; + /// Block header in the config savedata file struct SaveConfigBlockEntry { u32 block_id; ///< The id of the current block From f00e8d4b2b397b090ff7a7044c9909d3e700749b Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 8 Jun 2016 06:38:10 +0300 Subject: [PATCH 33/77] Service::CFG: add missing language --- src/core/hle/service/cfg/cfg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index 57e0821f3..bf544bd8d 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h @@ -35,7 +35,8 @@ enum SystemLanguage { LANGUAGE_KO = 7, LANGUAGE_NL = 8, LANGUAGE_PT = 9, - LANGUAGE_RU = 10 + LANGUAGE_RU = 10, + LANGUAGE_TW = 11 }; enum SoundOutputMode { From 324c8d21a4e5e7847c3c97d81757d0243ea9bb7f Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 1 Jun 2016 10:37:57 +0300 Subject: [PATCH 34/77] Service::CFG: add SetConfigInfoBlk4 --- src/core/hle/service/cfg/cfg.cpp | 45 +++++++++++++++++++++++++++--- src/core/hle/service/cfg/cfg.h | 30 +++++++++++++++++++- src/core/hle/service/cfg/cfg_i.cpp | 4 +-- src/core/hle/service/cfg/cfg_s.cpp | 2 +- 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 8e0848bf1..907a82301 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -223,6 +223,22 @@ void GetConfigInfoBlk8(Service::Interface* self) { Memory::WriteBlock(data_pointer, data.data(), data.size()); } +void SetConfigInfoBlk4(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 block_id = cmd_buff[1]; + u32 size = cmd_buff[2]; + VAddr data_pointer = cmd_buff[4]; + + if (!Memory::IsValidVirtualAddress(data_pointer)) { + cmd_buff[1] = -1; // TODO(Subv): Find the right error code + return; + } + + std::vector data(size); + Memory::ReadBlock(data_pointer, data.data(), data.size()); + cmd_buff[1] = Service::CFG::SetConfigInfoBlock(block_id, size, 0x4, data.data()).raw; +} + void UpdateConfigNANDSavegame(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = Service::CFG::UpdateConfigNANDSavegame().raw; @@ -233,13 +249,13 @@ void FormatConfig(Service::Interface* self) { cmd_buff[1] = Service::CFG::FormatConfig().raw; } -ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { +static ResultVal GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 flag) { // Read the header SaveFileConfig* config = reinterpret_cast(cfg_config_file_buffer.data()); auto itr = std::find_if(std::begin(config->block_entries), std::end(config->block_entries), [&](const SaveConfigBlockEntry& entry) { - return entry.block_id == block_id && (entry.flags & flag); + return entry.block_id == block_id; }); if (itr == std::end(config->block_entries)) { @@ -247,17 +263,38 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { return ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent); } + if ((itr->flags & flag) == 0) { + LOG_ERROR(Service_CFG, "Invalid flag %u for config block 0x%X with size %u", flag, block_id, size); + return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent); + } + if (itr->size != size) { LOG_ERROR(Service_CFG, "Invalid size %u for config block 0x%X with flags %u", size, block_id, flag); return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent); } + void* pointer; + // The data is located in the block header itself if the size is less than 4 bytes if (itr->size <= 4) - memcpy(output, &itr->offset_or_data, itr->size); + pointer = &itr->offset_or_data; else - memcpy(output, &cfg_config_file_buffer[itr->offset_or_data], itr->size); + pointer = &cfg_config_file_buffer[itr->offset_or_data]; + return MakeResult(pointer); +} + +ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) { + void* pointer; + CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); + memcpy(output, pointer, size); + return RESULT_SUCCESS; +} + +ResultCode SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) { + void* pointer; + CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); + memcpy(pointer, input, size); return RESULT_SUCCESS; } diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index bf544bd8d..4822433cf 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h @@ -184,6 +184,22 @@ void GetConfigInfoBlk2(Service::Interface* self); */ void GetConfigInfoBlk8(Service::Interface* self); +/** + * CFG::SetConfigInfoBlk4 service function + * Inputs: + * 0 : 0x04020082 / 0x08020082 + * 1 : Block ID + * 2 : Size + * 3 : Descriptor for the output buffer + * 4 : Output buffer pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * Note: + * The parameters order is different from GetConfigInfoBlk2/8's, + * where Block ID and Size are switched. + */ +void SetConfigInfoBlk4(Service::Interface* self); + /** * CFG::UpdateConfigNANDSavegame service function * Inputs: @@ -212,7 +228,19 @@ void FormatConfig(Service::Interface* self); * @param output A pointer where we will write the read data * @returns ResultCode indicating the result of the operation, 0 on success */ -ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output); +ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output); + +/** + * Reads data from input and writes to a block with the specified id and flag + * in the Config savegame buffer. + * The input size must match exactly the size of the target block + * @param block_id The id of the block we want to write + * @param size The size of the block we want to write + * @param flag The target block must have this flag set + * @param input A pointer where we will read data and write to Config savegame buffer + * @returns ResultCode indicating the result of the operation, 0 on success + */ +ResultCode SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input); /** * Creates a block with the specified id and writes the input data to the cfg savegame buffer in memory. diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp index b18060f6d..8b0db785f 100644 --- a/src/core/hle/service/cfg/cfg_i.cpp +++ b/src/core/hle/service/cfg/cfg_i.cpp @@ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, // cfg:i {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, - {0x04020082, nullptr, "SetConfigInfoBlk4"}, + {0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, {0x04040042, nullptr, "GetLocalFriendCodeSeedData"}, {0x04050000, nullptr, "GetLocalFriendCodeSeed"}, @@ -31,7 +31,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x04080042, nullptr, "SecureInfoGetSerialNo"}, {0x04090000, nullptr, "UpdateConfigBlk00040003"}, {0x08010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, - {0x08020082, nullptr, "SetConfigInfoBlk4"}, + {0x08020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, {0x08030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, {0x080400C2, nullptr, "CreateConfigInfoBlk"}, {0x08050000, nullptr, "DeleteConfigNANDSavefile"}, diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index e001f7687..12b458783 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp @@ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, // cfg:s {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, - {0x04020082, nullptr, "SetConfigInfoBlk4"}, + {0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, {0x04040042, nullptr, "GetLocalFriendCodeSeedData"}, {0x04050000, nullptr, "GetLocalFriendCodeSeed"}, From 457b6413e639adff0c4d3e313c62667a585e20cf Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 1 Jun 2016 10:40:52 +0300 Subject: [PATCH 35/77] Service::CFG: move known block ID to an enum --- src/core/hle/service/cfg/cfg.cpp | 36 ++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 907a82301..0f95464e6 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -40,6 +40,20 @@ struct SaveFileConfig { }; static_assert(sizeof(SaveFileConfig) == 0x455C, "SaveFileConfig header must be exactly 0x455C bytes"); +enum ConfigBlockID { + StereoCameraSettingsBlockID = 0x00050005, + SoundOutputModeBlockID = 0x00070001, + ConsoleUniqueIDBlockID = 0x00090001, + UsernameBlockID = 0x000A0000, + BirthdayBlockID = 0x000A0001, + LanguageBlockID = 0x000A0002, + CountryInfoBlockID = 0x000B0000, + CountryNameBlockID = 0x000B0001, + StateNameBlockID = 0x000B0002, + EULAVersionBlockID = 0x000D0000, + ConsoleModelBlockID = 0x000F0004, +}; + struct UsernameBlock { char16_t username[10]; ///< Exactly 20 bytes long, padded with zeros at the end if necessary u32 zero; @@ -372,25 +386,25 @@ ResultCode FormatConfig() { res = CreateConfigInfoBlk(0x00030001, 0x8, 0xE, zero_buffer); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x00050005, sizeof(STEREO_CAMERA_SETTINGS), 0xE, STEREO_CAMERA_SETTINGS.data()); + res = CreateConfigInfoBlk(StereoCameraSettingsBlockID, sizeof(STEREO_CAMERA_SETTINGS), 0xE, STEREO_CAMERA_SETTINGS.data()); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x00070001, sizeof(SOUND_OUTPUT_MODE), 0xE, &SOUND_OUTPUT_MODE); + res = CreateConfigInfoBlk(SoundOutputModeBlockID, sizeof(SOUND_OUTPUT_MODE), 0xE, &SOUND_OUTPUT_MODE); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x00090001, sizeof(CONSOLE_UNIQUE_ID), 0xE, &CONSOLE_UNIQUE_ID); + res = CreateConfigInfoBlk(ConsoleUniqueIDBlockID, sizeof(CONSOLE_UNIQUE_ID), 0xE, &CONSOLE_UNIQUE_ID); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x000A0000, sizeof(CONSOLE_USERNAME_BLOCK), 0xE, &CONSOLE_USERNAME_BLOCK); + res = CreateConfigInfoBlk(UsernameBlockID, sizeof(CONSOLE_USERNAME_BLOCK), 0xE, &CONSOLE_USERNAME_BLOCK); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x000A0001, sizeof(PROFILE_BIRTHDAY), 0xE, &PROFILE_BIRTHDAY); + res = CreateConfigInfoBlk(BirthdayBlockID, sizeof(PROFILE_BIRTHDAY), 0xE, &PROFILE_BIRTHDAY); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x000A0002, sizeof(CONSOLE_LANGUAGE), 0xE, &CONSOLE_LANGUAGE); + res = CreateConfigInfoBlk(LanguageBlockID, sizeof(CONSOLE_LANGUAGE), 0xE, &CONSOLE_LANGUAGE); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x000B0000, sizeof(COUNTRY_INFO), 0xE, &COUNTRY_INFO); + res = CreateConfigInfoBlk(CountryInfoBlockID, sizeof(COUNTRY_INFO), 0xE, &COUNTRY_INFO); if (!res.IsSuccess()) return res; u16_le country_name_buffer[16][0x40] = {}; @@ -399,10 +413,10 @@ ResultCode FormatConfig() { std::copy(region_name.cbegin(), region_name.cend(), country_name_buffer[i]); } // 0x000B0001 - Localized names for the profile Country - res = CreateConfigInfoBlk(0x000B0001, sizeof(country_name_buffer), 0xE, country_name_buffer); + res = CreateConfigInfoBlk(CountryNameBlockID, sizeof(country_name_buffer), 0xE, country_name_buffer); if (!res.IsSuccess()) return res; // 0x000B0002 - Localized names for the profile State/Province - res = CreateConfigInfoBlk(0x000B0002, sizeof(country_name_buffer), 0xE, country_name_buffer); + res = CreateConfigInfoBlk(StateNameBlockID, sizeof(country_name_buffer), 0xE, country_name_buffer); if (!res.IsSuccess()) return res; // 0x000B0003 - Unknown, related to country/address (zip code?) @@ -418,10 +432,10 @@ ResultCode FormatConfig() { if (!res.IsSuccess()) return res; // 0x000D0000 - Accepted EULA version - res = CreateConfigInfoBlk(0x000D0000, 0x4, 0xE, zero_buffer); + res = CreateConfigInfoBlk(EULAVersionBlockID, 0x4, 0xE, zero_buffer); if (!res.IsSuccess()) return res; - res = CreateConfigInfoBlk(0x000F0004, sizeof(CONSOLE_MODEL), 0xC, &CONSOLE_MODEL); + res = CreateConfigInfoBlk(ConsoleModelBlockID, sizeof(CONSOLE_MODEL), 0xC, &CONSOLE_MODEL); if (!res.IsSuccess()) return res; // 0x00170000 - Unknown From ab2eef396ad6633f67419daa1b473898bef1c43a Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 1 Jun 2016 10:42:37 +0300 Subject: [PATCH 36/77] Service::CFG/FS: add and refactor out utilities for front-end --- src/core/hle/service/cfg/cfg.cpp | 71 ++++++++++++++++++++++++++--- src/core/hle/service/cfg/cfg.h | 60 ++++++++++++++++++++++++ src/core/hle/service/fs/archive.cpp | 24 ++++++---- src/core/hle/service/fs/archive.h | 6 +++ 4 files changed, 146 insertions(+), 15 deletions(-) diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 0f95464e6..a5dc47322 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -449,11 +449,7 @@ ResultCode FormatConfig() { return RESULT_SUCCESS; } -void Init() { - AddService(new CFG_I_Interface); - AddService(new CFG_S_Interface); - AddService(new CFG_U_Interface); - +ResultCode LoadConfigNANDSaveFile() { // Open the SystemSaveData archive 0x00010017 FileSys::Path archive_path(cfg_system_savedata_id); auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); @@ -481,14 +477,75 @@ void Init() { if (config_result.Succeeded()) { auto config = config_result.MoveFrom(); config->backend->Read(0, CONFIG_SAVEFILE_SIZE, cfg_config_file_buffer.data()); - return; + return RESULT_SUCCESS; } - FormatConfig(); + return FormatConfig(); +} + +void Init() { + AddService(new CFG_I_Interface); + AddService(new CFG_S_Interface); + AddService(new CFG_U_Interface); + + LoadConfigNANDSaveFile(); } void Shutdown() { } +void SetUsername(const std::u16string& name) { + ASSERT(name.size() <= 10); + UsernameBlock block{}; + name.copy(block.username, name.size()); + SetConfigInfoBlock(UsernameBlockID, sizeof(block), 4, &block); +} + +std::u16string GetUsername() { + UsernameBlock block; + GetConfigInfoBlock(UsernameBlockID, sizeof(block), 8, &block); + + // the username string in the block isn't null-terminated, + // so we need to find the end manually. + std::u16string username(block.username, ARRAY_SIZE(block.username)); + const size_t pos = username.find(u'\0'); + if (pos != std::u16string::npos) + username.erase(pos); + return username; +} + +void SetBirthday(u8 month, u8 day) { + BirthdayBlock block = { month, day }; + SetConfigInfoBlock(BirthdayBlockID, sizeof(block), 4, &block); +} + +std::tuple GetBirthday() { + BirthdayBlock block; + GetConfigInfoBlock(BirthdayBlockID, sizeof(block), 8, &block); + return std::make_tuple(block.month, block.day); +} + +void SetSystemLanguage(SystemLanguage language) { + u8 block = language; + SetConfigInfoBlock(LanguageBlockID, sizeof(block), 4, &block); +} + +SystemLanguage GetSystemLanguage() { + u8 block; + GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block); + return static_cast(block); +} + +void SetSoundOutputMode(SoundOutputMode mode) { + u8 block = mode; + SetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 4, &block); +} + +SoundOutputMode GetSoundOutputMode() { + u8 block; + GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block); + return static_cast(block); +} + } // namespace CFG } // namespace Service diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index 4822433cf..18f60f4ca 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/common_types.h" @@ -271,11 +272,70 @@ ResultCode UpdateConfigNANDSavegame(); */ ResultCode FormatConfig(); +/** + * Open the config savegame file and load it to the memory buffer + * @returns ResultCode indicating the result of the operation, 0 on success + */ +ResultCode LoadConfigNANDSaveFile(); + /// Initialize the config service void Init(); /// Shutdown the config service void Shutdown(); +// Utilities for frontend to set config data. +// Note: before calling these functions, LoadConfigNANDSaveFile should be called, +// and UpdateConfigNANDSavegame should be called after making changes to config data. + +/** + * Sets the username in config savegame. + * @param name the username to set. The maximum size is 10 in char16_t. + */ +void SetUsername(const std::u16string& name); + +/** + * Gets the username from config savegame. + * @returns the username + */ +std::u16string GetUsername(); + +/** + * Sets the profile birthday in config savegame. + * @param month the month of birthday. + * @param day the day of the birthday. + */ +void SetBirthday(u8 month, u8 day); + +/** + * Gets the profile birthday from the config savegame. + * @returns a tuple of (month, day) of birthday + */ +std::tuple GetBirthday(); + +/** + * Sets the system language in config savegame. + * @param language the system language to set. + */ +void SetSystemLanguage(SystemLanguage language); + +/** + * Gets the system language from config savegame. + * @returns the system language + */ +SystemLanguage GetSystemLanguage(); + +/** + * Sets the sound output mode in config savegame. + * @param mode the sound output mode to set + */ +void SetSoundOutputMode(SoundOutputMode mode); + +/** + * Gets the sound output mode from config savegame. + * @returns the sound output mode + */ +SoundOutputMode GetSoundOutputMode(); + } // namespace CFG } // namespace Service diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 81b9abe4c..cc7af7218 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -255,7 +255,7 @@ using FileSys::ArchiveFactory; /** * Map of registered archives, identified by id code. Once an archive is registered here, it is - * never removed until the FS service is shut down. + * never removed until UnregisterArchiveTypes is called. */ static boost::container::flat_map> id_code_map; @@ -516,12 +516,7 @@ ResultCode CreateSystemSaveData(u32 high, u32 low) { return RESULT_SUCCESS; } -/// Initialize archives -void ArchiveInit() { - next_handle = 1; - - AddService(new FS::Interface); - +void RegisterArchiveTypes() { // TODO(Subv): Add the other archive types (see here for the known types: // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). @@ -558,10 +553,23 @@ void ArchiveInit() { RegisterArchiveType(std::move(systemsavedata_factory), ArchiveIdCode::SystemSaveData); } +void UnregisterArchiveTypes() { + id_code_map.clear(); +} + +/// Initialize archives +void ArchiveInit() { + next_handle = 1; + + AddService(new FS::Interface); + + RegisterArchiveTypes(); +} + /// Shutdown archives void ArchiveShutdown() { handle_map.clear(); - id_code_map.clear(); + UnregisterArchiveTypes(); } } // namespace FS diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 006606740..f7a50a3a7 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -235,5 +235,11 @@ void ArchiveInit(); /// Shutdown archives void ArchiveShutdown(); +/// Register all archive types +void RegisterArchiveTypes(); + +/// Unregister all archive types +void UnregisterArchiveTypes(); + } // namespace FS } // namespace Service From 8752f07e8e8165badec93535ab32381f8e84db3e Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 18 Jun 2016 21:48:33 -0500 Subject: [PATCH 37/77] HLE/FS: Document some command parameters and implemented command 0x08560240 (CreateLegacySystemSaveData) --- src/core/hle/service/fs/fs_user.cpp | 53 +++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 7df7da5a4..937868747 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -645,20 +645,19 @@ static void DeleteSystemSaveData(Service::Interface* self) { * FS_User::CreateSystemSaveData service function. * Inputs: * 0 : 0x08560240 - * 1 : High word of the SystemSaveData id to create - * 2 : Low word of the SystemSaveData id to create - * 3 : Unknown - * 4 : Unknown - * 5 : Unknown - * 6 : Unknown - * 7 : Unknown - * 8 : Unknown - * 9 : Unknown (Memory address) + * 1 : u8 MediaType of the system save data + * 2 : SystemSaveData id to create + * 3 : Total size + * 4 : Block size + * 5 : Number of directories + * 6 : Number of files + * 7 : Directory bucket count + * 8 : File bucket count + * 9 : u8 Whether to duplicate data or not * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ static void CreateSystemSaveData(Service::Interface* self) { - // TODO(Subv): Figure out the other parameters. u32* cmd_buff = Kernel::GetCommandBuffer(); u32 savedata_high = cmd_buff[1]; u32 savedata_low = cmd_buff[2]; @@ -671,6 +670,38 @@ static void CreateSystemSaveData(Service::Interface* self) { cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw; } +/** + * FS_User::CreateLegacySystemSaveData service function. + * This function appears to be obsolete and seems to have been replaced by + * command 0x08560240 (CreateSystemSaveData). + * + * Inputs: + * 0 : 0x08100200 + * 1 : SystemSaveData id to create + * 2 : Total size + * 3 : Block size + * 4 : Number of directories + * 5 : Number of files + * 6 : Directory bucket count + * 7 : File bucket count + * 8 : u8 Duplicate data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void CreateLegacySystemSaveData(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 savedata_id = cmd_buff[1]; + + LOG_WARNING(Service_FS, "(STUBBED) savedata_id=%08X cmd_buff[3]=%08X " + "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " + "cmd_buff[9]=%08X", savedata_id, cmd_buff[3], cmd_buff[4], cmd_buff[5], + cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]); + + cmd_buff[0] = IPC::MakeHeader(0x810, 0x1, 0); + // With this command, the SystemSaveData always has save_high = 0 (Always created in the NAND) + cmd_buff[1] = CreateSystemSaveData(0, savedata_id).raw; +} + /** * FS_User::InitializeWithSdkVersion service function. * Inputs: @@ -820,7 +851,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x080D0144, nullptr, "ControlArchive"}, {0x080E0080, CloseArchive, "CloseArchive"}, {0x080F0180, FormatThisUserSaveData, "FormatThisUserSaveData"}, - {0x08100200, nullptr, "CreateSystemSaveData"}, + {0x08100200, CreateLegacySystemSaveData, "CreateLegacySystemSaveData"}, {0x08110040, nullptr, "DeleteSystemSaveData"}, {0x08120080, GetFreeBytes, "GetFreeBytes"}, {0x08130000, nullptr, "GetCardType"}, From e06f2705f07b71e34ce503b045f6a81e82db91e9 Mon Sep 17 00:00:00 2001 From: mailwl Date: Wed, 30 Mar 2016 15:52:59 +0300 Subject: [PATCH 38/77] HLE/Applets: Implement ErrEula applet --- src/core/CMakeLists.txt | 2 + src/core/hle/applets/applet.cpp | 5 +++ src/core/hle/applets/erreula.cpp | 72 ++++++++++++++++++++++++++++++++ src/core/hle/applets/erreula.h | 31 ++++++++++++++ src/core/hle/service/apt/apt.h | 8 ++++ 5 files changed, 118 insertions(+) create mode 100644 src/core/hle/applets/erreula.cpp create mode 100644 src/core/hle/applets/erreula.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 02d902bb5..0773339a9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -27,6 +27,7 @@ set(SRCS hle/config_mem.cpp hle/hle.cpp hle/applets/applet.cpp + hle/applets/erreula.cpp hle/applets/mii_selector.cpp hle/applets/swkbd.cpp hle/kernel/address_arbiter.cpp @@ -168,6 +169,7 @@ set(HEADERS hle/function_wrappers.h hle/hle.h hle/applets/applet.h + hle/applets/erreula.h hle/applets/mii_selector.h hle/applets/swkbd.h hle/kernel/address_arbiter.h diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 90e134437..ccf35fa07 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -12,6 +12,7 @@ #include "core/core_timing.h" #include "core/hle/applets/applet.h" +#include "core/hle/applets/erreula.h" #include "core/hle/applets/mii_selector.h" #include "core/hle/applets/swkbd.h" #include "core/hle/result.h" @@ -52,6 +53,10 @@ ResultCode Applet::Create(Service::APT::AppletId id) { case Service::APT::AppletId::Ed2: applets[id] = std::make_shared(id); break; + case Service::APT::AppletId::Error: + case Service::APT::AppletId::Error2: + applets[id] = std::make_shared(id); + break; default: LOG_ERROR(Service_APT, "Could not create applet %u", id); // TODO(Subv): Find the right error code diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp new file mode 100644 index 000000000..92a4b2323 --- /dev/null +++ b/src/core/hle/applets/erreula.cpp @@ -0,0 +1,72 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/string_util.h" + +#include "core/hle/applets/erreula.h" +#include "core/hle/service/apt/apt.h" + +namespace HLE { +namespace Applets { + +ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { + if (parameter.signal != static_cast(Service::APT::SignalType::LibAppJustStarted)) { + LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); + UNIMPLEMENTED(); + // TODO(Subv): Find the right error code + return ResultCode(-1); + } + + // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory. + // Create the SharedMemory that will hold the framebuffer data + Service::APT::CaptureBufferInfo capture_info; + ASSERT(sizeof(capture_info) == parameter.buffer.size()); + + memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); + + // TODO: allocated memory never released + using Kernel::MemoryPermission; + // Allocate a heap block of the required size for this applet. + heap_memory = std::make_shared>(capture_info.size); + // Create a SharedMemory that directly points to this heap block. + framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(), + MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + "ErrEula Memory"); + + // Send the response message with the newly created SharedMemory + Service::APT::MessageParameter result; + result.signal = static_cast(Service::APT::SignalType::LibAppFinished); + result.buffer.clear(); + result.destination_id = static_cast(Service::APT::AppletId::Application); + result.sender_id = static_cast(id); + result.object = framebuffer_memory; + + Service::APT::SendParameter(result); + return RESULT_SUCCESS; +} + +ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) { + started = true; + + // TODO(Subv): Set the expected fields in the response buffer before resending it to the application. + // TODO(Subv): Reverse the parameter format for the ErrEula applet + + // Let the application know that we're closing + Service::APT::MessageParameter message; + message.buffer.resize(parameter.buffer.size()); + std::fill(message.buffer.begin(), message.buffer.end(), 0); + message.signal = static_cast(Service::APT::SignalType::LibAppClosed); + message.destination_id = static_cast(Service::APT::AppletId::Application); + message.sender_id = static_cast(id); + Service::APT::SendParameter(message); + + started = false; + return RESULT_SUCCESS; +} + +void ErrEula::Update() { +} + +} // namespace Applets +} // namespace HLE diff --git a/src/core/hle/applets/erreula.h b/src/core/hle/applets/erreula.h new file mode 100644 index 000000000..9fe72ae07 --- /dev/null +++ b/src/core/hle/applets/erreula.h @@ -0,0 +1,31 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/applets/applet.h" +#include "core/hle/kernel/shared_memory.h" + +namespace HLE { +namespace Applets { + +class ErrEula final : public Applet { +public: + explicit ErrEula(Service::APT::AppletId id): Applet(id) { } + + ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; + ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; + void Update() override; + bool IsRunning() const override { return started; } + + /// This SharedMemory will be created when we receive the LibAppJustStarted message. + /// It holds the framebuffer info retrieved by the application with GSPGPU::ImportDisplayCaptureInfo + Kernel::SharedPtr framebuffer_memory; +private: + /// Whether this applet is currently running instead of the host application or not. + bool started = false; +}; + +} // namespace Applets +} // namespace HLE diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 76b3a3807..53cee4867 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -66,6 +66,8 @@ enum class AppletId : u32 { InstructionManual = 0x115, Notifications = 0x116, Miiverse = 0x117, + MiiversePost = 0x118, + AmiiboSettings = 0x119, SoftwareKeyboard1 = 0x201, Ed1 = 0x202, PnoteApp = 0x204, @@ -78,6 +80,12 @@ enum class AppletId : u32 { AnyLibraryApplet = 0x400, SoftwareKeyboard2 = 0x401, Ed2 = 0x402, + PnoteApp2 = 0x404, + SnoteApp2 = 0x405, + Error2 = 0x406, + Mint2 = 0x407, + Extrapad2 = 0x408, + Memolib2 = 0x409, }; enum class StartupArgumentType : u32 { From f87bb8ba0a7fa0ec3e0ae18b38c894d637c39fa0 Mon Sep 17 00:00:00 2001 From: JamePeng Date: Wed, 29 Jun 2016 20:47:22 +0800 Subject: [PATCH 39/77] Fix the errorcode of archive handle --- src/core/hle/result.h | 1 + src/core/hle/service/fs/archive.cpp | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 68d6f5a87..268a8dad2 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -20,6 +20,7 @@ enum class ErrorDescription : u32 { WrongPermission = 46, OS_InvalidBufferDescriptor = 48, WrongAddress = 53, + FS_ArchiveNotMounted = 101, FS_NotFound = 120, FS_AlreadyExists = 190, FS_InvalidOpenFlags = 230, diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 81b9abe4c..f4acc4895 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -58,6 +58,10 @@ namespace FS { const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::FS, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); +/// Returned when a function is passed an invalid archive handle. +const ResultCode ERR_INVALID_ARCHIVE_HANDLE(ErrorDescription::FS_ArchiveNotMounted, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Status); // 0xC8804465 + // Command to access archive file enum class FileCommand : u32 { Dummy1 = 0x000100C6, @@ -292,7 +296,7 @@ ResultVal OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi ResultCode CloseArchive(ArchiveHandle handle) { if (handle_map.erase(handle) == 0) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; else return RESULT_SUCCESS; } @@ -314,7 +318,7 @@ ResultVal> OpenFileFromArchive(ArchiveHandle archive_han const FileSys::Path& path, const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; auto backend = archive->OpenFile(path, mode); if (backend.Failed()) @@ -327,7 +331,7 @@ ResultVal> OpenFileFromArchive(ArchiveHandle archive_han ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; return archive->DeleteFile(path); } @@ -337,7 +341,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil ArchiveBackend* src_archive = GetArchive(src_archive_handle); ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; if (src_archive == dest_archive) { if (src_archive->RenameFile(src_path, dest_path)) @@ -356,7 +360,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; if (archive->DeleteDirectory(path)) return RESULT_SUCCESS; @@ -367,7 +371,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u64 file_size) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; return archive->CreateFile(path, file_size); } @@ -375,7 +379,7 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; if (archive->CreateDirectory(path)) return RESULT_SUCCESS; @@ -388,7 +392,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons ArchiveBackend* src_archive = GetArchive(src_archive_handle); ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; if (src_archive == dest_archive) { if (src_archive->RenameDirectory(src_path, dest_path)) @@ -408,7 +412,7 @@ ResultVal> OpenDirectoryFromArchive(ArchiveHandle a const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; std::unique_ptr backend = archive->OpenDirectory(path); if (backend == nullptr) { @@ -423,7 +427,7 @@ ResultVal> OpenDirectoryFromArchive(ArchiveHandle a ResultVal GetFreeBytesInArchive(ArchiveHandle archive_handle) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_HANDLE; + return ERR_INVALID_ARCHIVE_HANDLE; return MakeResult(archive->GetFreeBytes()); } From ec3e99eec762a380322b0c058e30a69e92fb3c1d Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 1 Jun 2016 10:43:33 +0300 Subject: [PATCH 40/77] Qt: add system settings config tab --- src/citra_qt/CMakeLists.txt | 3 + src/citra_qt/configure.ui | 11 ++ src/citra_qt/configure_dialog.cpp | 9 +- src/citra_qt/configure_dialog.h | 3 +- src/citra_qt/configure_system.cpp | 136 ++++++++++++++++ src/citra_qt/configure_system.h | 38 +++++ src/citra_qt/configure_system.ui | 252 ++++++++++++++++++++++++++++++ src/citra_qt/main.cpp | 2 +- 8 files changed, 450 insertions(+), 4 deletions(-) create mode 100644 src/citra_qt/configure_system.cpp create mode 100644 src/citra_qt/configure_system.h create mode 100644 src/citra_qt/configure_system.ui diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 43a766053..017b43871 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRCS configure_debug.cpp configure_dialog.cpp configure_general.cpp + configure_system.cpp game_list.cpp hotkeys.cpp main.cpp @@ -52,6 +53,7 @@ set(HEADERS configure_debug.h configure_dialog.h configure_general.h + configure_system.h game_list.h game_list_p.h hotkeys.h @@ -69,6 +71,7 @@ set(UIS configure_audio.ui configure_debug.ui configure_general.ui + configure_system.ui hotkeys.ui main.ui ) diff --git a/src/citra_qt/configure.ui b/src/citra_qt/configure.ui index e1624bbef..4a9c52650 100644 --- a/src/citra_qt/configure.ui +++ b/src/citra_qt/configure.ui @@ -24,6 +24,11 @@ General + + + System + + Input @@ -57,6 +62,12 @@
configure_general.h
1 + + ConfigureSystem + QWidget +
configure_system.h
+ 1 +
ConfigureAudio QWidget diff --git a/src/citra_qt/configure_dialog.cpp b/src/citra_qt/configure_dialog.cpp index 2f0317fe0..77c266d01 100644 --- a/src/citra_qt/configure_dialog.cpp +++ b/src/citra_qt/configure_dialog.cpp @@ -9,9 +9,10 @@ #include "core/settings.h" -ConfigureDialog::ConfigureDialog(QWidget *parent) : +ConfigureDialog::ConfigureDialog(QWidget *parent, bool running) : QDialog(parent), - ui(new Ui::ConfigureDialog) + ui(new Ui::ConfigureDialog), + emulation_running(running) { ui->setupUi(this); this->setConfiguration(); @@ -21,10 +22,14 @@ ConfigureDialog::~ConfigureDialog() { } void ConfigureDialog::setConfiguration() { + // System tab needs set manually + // depending on whether emulation is running + ui->systemTab->setConfiguration(emulation_running); } void ConfigureDialog::applyConfiguration() { ui->generalTab->applyConfiguration(); + ui->systemTab->applyConfiguration(); ui->audioTab->applyConfiguration(); ui->debugTab->applyConfiguration(); } diff --git a/src/citra_qt/configure_dialog.h b/src/citra_qt/configure_dialog.h index 89020eeb4..305b33bdf 100644 --- a/src/citra_qt/configure_dialog.h +++ b/src/citra_qt/configure_dialog.h @@ -16,7 +16,7 @@ class ConfigureDialog : public QDialog Q_OBJECT public: - explicit ConfigureDialog(QWidget *parent = nullptr); + explicit ConfigureDialog(QWidget *parent, bool emulation_running); ~ConfigureDialog(); void applyConfiguration(); @@ -26,4 +26,5 @@ private: private: std::unique_ptr ui; + bool emulation_running; }; diff --git a/src/citra_qt/configure_system.cpp b/src/citra_qt/configure_system.cpp new file mode 100644 index 000000000..4f0d4dbfe --- /dev/null +++ b/src/citra_qt/configure_system.cpp @@ -0,0 +1,136 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "citra_qt/configure_system.h" +#include "citra_qt/ui_settings.h" +#include "ui_configure_system.h" + +#include "core/hle/service/fs/archive.h" +#include "core/hle/service/cfg/cfg.h" + +static const std::array days_in_month = {{ + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}}; + +ConfigureSystem::ConfigureSystem(QWidget *parent) : + QWidget(parent), + ui(new Ui::ConfigureSystem) { + ui->setupUi(this); + + connect(ui->combo_birthmonth, SIGNAL(currentIndexChanged(int)), SLOT(updateBirthdayComboBox(int))); +} + +ConfigureSystem::~ConfigureSystem() { +} + +void ConfigureSystem::setConfiguration(bool emulation_running) { + enabled = !emulation_running; + + if (!enabled) { + ReadSystemSettings(); + ui->group_system_settings->setEnabled(false); + } else { + // This tab is enabled only when game is not running (i.e. all service are not initialized). + // Temporarily register archive types and load the config savegame file to memory. + Service::FS::RegisterArchiveTypes(); + ResultCode result = Service::CFG::LoadConfigNANDSaveFile(); + Service::FS::UnregisterArchiveTypes(); + + if (result.IsError()) { + ui->label_disable_info->setText(tr("Failed to load system settings data.")); + ui->group_system_settings->setEnabled(false); + enabled = false; + return; + } + + ReadSystemSettings(); + ui->label_disable_info->hide(); + } +} + +void ConfigureSystem::ReadSystemSettings() { + // set username + username = Service::CFG::GetUsername(); + // ui->edit_username->setText(QString::fromStdU16String(username)); // TODO(wwylele): Use this when we move to Qt 5.5 + ui->edit_username->setText(QString::fromUtf16(reinterpret_cast(username.data()))); + + // set birthday + std::tie(birthmonth, birthday) = Service::CFG::GetBirthday(); + ui->combo_birthmonth->setCurrentIndex(birthmonth - 1); + ui->combo_birthday->setCurrentIndex(birthday - 1); + + // set system language + language_index = Service::CFG::GetSystemLanguage(); + ui->combo_language->setCurrentIndex(language_index); + + // set sound output mode + sound_index = Service::CFG::GetSoundOutputMode(); + ui->combo_sound->setCurrentIndex(sound_index); +} + +void ConfigureSystem::applyConfiguration() { + if (!enabled) + return; + + bool modified = false; + + // apply username + // std::u16string new_username = ui->edit_username->text().toStdU16String(); // TODO(wwylele): Use this when we move to Qt 5.5 + std::u16string new_username(reinterpret_cast(ui->edit_username->text().utf16())); + if (new_username != username) { + Service::CFG::SetUsername(new_username); + modified = true; + } + + // apply birthday + int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1; + int new_birthday = ui->combo_birthday->currentIndex() + 1; + if (birthmonth != new_birthmonth || birthday != new_birthday) { + Service::CFG::SetBirthday(new_birthmonth, new_birthday); + modified = true; + } + + // apply language + int new_language = ui->combo_language->currentIndex(); + if (language_index != new_language) { + Service::CFG::SetSystemLanguage(static_cast(new_language)); + modified = true; + } + + // apply sound + int new_sound = ui->combo_sound->currentIndex(); + if (sound_index != new_sound) { + Service::CFG::SetSoundOutputMode(static_cast(new_sound)); + modified = true; + } + + // update the config savegame if any item is modified. + if (modified) + Service::CFG::UpdateConfigNANDSavegame(); +} + +void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) { + if (birthmonth_index < 0 || birthmonth_index >= 12) + return; + + // store current day selection + int birthday_index = ui->combo_birthday->currentIndex(); + + // get number of days in the new selected month + int days = days_in_month[birthmonth_index]; + + // if the selected day is out of range, + // reset it to 1st + if (birthday_index < 0 || birthday_index >= days) + birthday_index = 0; + + // update the day combo box + ui->combo_birthday->clear(); + for (int i = 1; i <= days; ++i) { + ui->combo_birthday->addItem(QString::number(i)); + } + + // restore the day selection + ui->combo_birthday->setCurrentIndex(birthday_index); +} diff --git a/src/citra_qt/configure_system.h b/src/citra_qt/configure_system.h new file mode 100644 index 000000000..1f5577070 --- /dev/null +++ b/src/citra_qt/configure_system.h @@ -0,0 +1,38 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +namespace Ui { +class ConfigureSystem; +} + +class ConfigureSystem : public QWidget +{ + Q_OBJECT + +public: + explicit ConfigureSystem(QWidget *parent = nullptr); + ~ConfigureSystem(); + + void applyConfiguration(); + void setConfiguration(bool emulation_running); + +public slots: + void updateBirthdayComboBox(int birthmonth_index); + +private: + void ReadSystemSettings(); + + std::unique_ptr ui; + bool enabled; + + std::u16string username; + int birthmonth, birthday; + int language_index; + int sound_index; +}; diff --git a/src/citra_qt/configure_system.ui b/src/citra_qt/configure_system.ui new file mode 100644 index 000000000..6a906b61b --- /dev/null +++ b/src/citra_qt/configure_system.ui @@ -0,0 +1,252 @@ + + + ConfigureSystem + + + + 0 + 0 + 360 + 377 + + + + Form + + + + + + + + System Settings + + + + + + Username + + + + + + + + 0 + 0 + + + + 10 + + + + + + + Birthday + + + + + + + + + + January + + + + + February + + + + + March + + + + + April + + + + + May + + + + + June + + + + + July + + + + + August + + + + + September + + + + + October + + + + + November + + + + + December + + + + + + + + + + + + + Language + + + + + + + + Japanese (日本語) + + + + + English + + + + + French (français) + + + + + German (Deutsch) + + + + + Italian (italiano) + + + + + Spanish (español) + + + + + Simplified Chinese (简体中文) + + + + + Korean (한국어) + + + + + Dutch (Nederlands) + + + + + Portuguese (português) + + + + + Russian (Русский) + + + + + Traditional Chinese (正體中文) + + + + + + + + Sound output mode + + + + + + + + Mono + + + + + Stereo + + + + + Surround + + + + + + + + + + + System settings are available only when game is not running. + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 0ed1ffa5a..6fe5d7a3f 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -508,7 +508,7 @@ void GMainWindow::ToggleWindowMode() { } void GMainWindow::OnConfigure() { - ConfigureDialog configureDialog(this); + ConfigureDialog configureDialog(this, emulation_running); auto result = configureDialog.exec(); if (result == QDialog::Accepted) { From d5aa47478895386a59f59a650d7391e3598e6739 Mon Sep 17 00:00:00 2001 From: JamePeng Date: Thu, 14 Jul 2016 18:26:43 +0800 Subject: [PATCH 41/77] Correct APT::0x00550040 and APT::0x00560000 function --- src/core/hle/service/apt/apt.cpp | 15 +++++++++------ src/core/hle/service/apt/apt.h | 26 ++++++++++++++++---------- src/core/hle/service/apt/apt_a.cpp | 4 ++-- src/core/hle/service/apt/apt_s.cpp | 4 ++-- src/core/hle/service/apt/apt_u.cpp | 4 ++-- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 1e54a53dd..14d661b38 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -37,6 +37,8 @@ static u32 cpu_percent; ///< CPU time available to the running application // APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode static u8 unknown_ns_state_field; +static ScreencapPostPermission screen_capture_post_permission; + /// Parameter data to be returned in the next call to Glance/ReceiveParameter static MessageParameter next_parameter; @@ -382,23 +384,23 @@ void StartLibraryApplet(Service::Interface* self) { cmd_buff[1] = applet->Start(parameter).raw; } -void SetNSStateField(Service::Interface* self) { +void SetScreenCapPostPermission(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - unknown_ns_state_field = cmd_buff[1]; + screen_capture_post_permission = static_cast(cmd_buff[1] & 0xF); cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0); cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_APT, "(STUBBED) unknown_ns_state_field=%u", unknown_ns_state_field); + LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission); } -void GetNSStateField(Service::Interface* self) { +void GetScreenCapPostPermission(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0); cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[8] = unknown_ns_state_field; - LOG_WARNING(Service_APT, "(STUBBED) unknown_ns_state_field=%u", unknown_ns_state_field); + cmd_buff[2] = static_cast(screen_capture_post_permission); + LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission); } void GetAppletInfo(Service::Interface* self) { @@ -493,6 +495,7 @@ void Init() { cpu_percent = 0; unknown_ns_state_field = 0; + screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value // TODO(bunnei): Check if these are created in Initialize or on APT process startup. notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification"); diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 53cee4867..077a6a316 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -94,6 +94,13 @@ enum class StartupArgumentType : u32 { OtherMedia = 2, }; +enum class ScreencapPostPermission : u32 { + CleanThePermission = 0, //TODO(JamePeng): verify what "zero" means + NoExplicitSetting = 1, + EnableScreenshotPostingToMiiverse = 2, + DisableScreenshotPostingToMiiverse = 3 +}; + /// Send a parameter to the currently-running application, which will read it via ReceiveParameter void SendParameter(const MessageParameter& parameter); @@ -383,25 +390,24 @@ void StartLibraryApplet(Service::Interface* self); void GetStartupArgument(Service::Interface* self); /** - * APT::SetNSStateField service function + * APT::SetScreenCapPostPermission service function * Inputs: - * 1 : u8 NS state field + * 0 : Header Code[0x00550040] + * 1 : u8 The screenshot posting permission * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * Note: - * This writes the input u8 to a NS state field. */ -void SetNSStateField(Service::Interface* self); +void SetScreenCapPostPermission(Service::Interface* self); /** - * APT::GetNSStateField service function + * APT::GetScreenCapPostPermission service function + * Inputs: + * 0 : Header Code[0x00560000] * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * 8 : u8 NS state field - * Note: - * This returns a u8 NS state field(which can be set by cmd 0x00550040), at cmdreply+8. + * 2 : u8 The screenshot posting permission */ -void GetNSStateField(Service::Interface* self); +void GetScreenCapPostPermission(Service::Interface* self); /** * APT::CheckNew3DSApp service function diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index 223c0a8bd..6c44c491c 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -33,8 +33,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, {0x00510080, GetStartupArgument, "GetStartupArgument"}, - {0x00550040, SetNSStateField, "SetNSStateField?"}, - {0x00560000, GetNSStateField, "GetNSStateField?"}, + {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, + {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"} }; diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index f5c52fa3d..c70f2201f 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00510080, GetStartupArgument, "GetStartupArgument"}, {0x00520104, nullptr, "Wrap1"}, {0x00530104, nullptr, "Unwrap1"}, - {0x00550040, SetNSStateField, "SetNSStateField?" }, - {0x00560000, GetNSStateField, "GetNSStateField?" }, + {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, + {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x00580002, nullptr, "GetProgramID"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"} diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index 0e60bd34f..7bb804ffa 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00510080, GetStartupArgument, "GetStartupArgument"}, {0x00520104, nullptr, "Wrap1"}, {0x00530104, nullptr, "Unwrap1"}, - {0x00550040, SetNSStateField, "SetNSStateField?"}, - {0x00560000, GetNSStateField, "GetNSStateField?"}, + {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, + {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x00580002, nullptr, "GetProgramID"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"} From c7125f37aa5325f84d615eaf3b8fa2e67eb7d800 Mon Sep 17 00:00:00 2001 From: Lectem Date: Thu, 21 Jul 2016 10:28:52 +0200 Subject: [PATCH 42/77] Fixes SDL2.dll copy to bindir on windows --- externals/cmake-modules/FindSDL2.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/externals/cmake-modules/FindSDL2.cmake b/externals/cmake-modules/FindSDL2.cmake index 9b8daa0d1..22ce752c5 100644 --- a/externals/cmake-modules/FindSDL2.cmake +++ b/externals/cmake-modules/FindSDL2.cmake @@ -3,6 +3,7 @@ # SDL2_LIBRARY, the name of the library to link against # SDL2_FOUND, if false, do not try to link to SDL2 # SDL2_INCLUDE_DIR, where to find SDL.h +# SDL2_DLL_DIR, where to find SDL2.dll if it exists # # This module responds to the the flag: # SDL2_BUILDING_LIBRARY @@ -149,6 +150,14 @@ FIND_LIBRARY(SDL2_LIBRARY_TEMP ) IF(SDL2_LIBRARY_TEMP) + if(MSVC) + get_filename_component(SDL2_DLL_DIR_TEMP ${SDL2_LIBRARY_TEMP} DIRECTORY) + if(EXISTS ${SDL2_DLL_DIR_TEMP}/SDL2.dll) + set(SDL2_DLL_DIR ${SDL2_DLL_DIR_TEMP}) + unset(SDL2_DLL_DIR_TEMP) + endif() + endif() + FIND_PATH(SDL2_INCLUDE_DIR SDL.h HINTS $ENV{SDL2DIR} From 78b97ee36433121b12d67d465f043cd7d75ec7ee Mon Sep 17 00:00:00 2001 From: Dale Whinham Date: Thu, 21 Jul 2016 21:33:54 +0100 Subject: [PATCH 43/77] CMake: Fix Info.plist template for citra_qt/OSX The Info.plist template incorrectly uses parentheses instead of curly braces, which means that building the .app bundle using regular 'make' results in the variable not being replaced, and hence the app bundle won't start because the executable name is incorrect. This commit fixes this issue. --- src/citra_qt/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/citra_qt/Info.plist b/src/citra_qt/Info.plist index 4c89e128b..7d46b39d1 100644 --- a/src/citra_qt/Info.plist +++ b/src/citra_qt/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion English CFBundleExecutable - $(EXECUTABLE_NAME) + ${EXECUTABLE_NAME} CFBundleGetInfoString CFBundleIconFile From 00c34e4df73add0f3eda53a71ea23125ac343971 Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 20 Jul 2016 20:20:01 +0800 Subject: [PATCH 44/77] HLE: implement system time --- src/core/hle/shared_page.cpp | 57 ++++++++++++++++++++++++++++++++++++ src/core/hle/shared_page.h | 5 ++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 2a1caeaac..4d9272923 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include +#include +#include "core/core_timing.h" #include "core/hle/shared_page.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -12,6 +15,57 @@ namespace SharedPage { SharedPageDef shared_page; +static int update_time_event; + +/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond. +static u64 GetSystemTime() { + auto now = std::chrono::system_clock::now(); + + // 3DS system does't allow user to set a time before Jan 1 2000, + // so we use it as an auxiliary epoch to calculate the console time. + std::tm epoch_tm; + epoch_tm.tm_sec = 0; + epoch_tm.tm_min = 0; + epoch_tm.tm_hour = 0; + epoch_tm.tm_mday = 1; + epoch_tm.tm_mon = 0; + epoch_tm.tm_year = 100; + epoch_tm.tm_isdst = 0; + auto epoch = std::chrono::system_clock::from_time_t(std::mktime(&epoch_tm)); + + // 3DS console time uses Jan 1 1900 as internal epoch, + // so we use the milliseconds between 1900 and 2000 as base console time + u64 console_time = 3155673600000ULL; + + // Only when system time is after 2000, we set it as 3DS system time + if (now > epoch) { + console_time += std::chrono::duration_cast(now - epoch).count(); + } + + // If the system time is in daylight saving, we give an additional hour to console time + std::time_t now_time_t = std::chrono::system_clock::to_time_t(now); + std::tm* now_tm = std::localtime(&now_time_t); + if (now_tm && now_tm->tm_isdst > 0) + console_time += 60 * 60 * 1000; + + return console_time; +} + +static void UpdateTimeCallback(u64 userdata, int cycles_late) { + DateTime& date_time = shared_page.date_time_counter % 2 ? + shared_page.date_time_0 : shared_page.date_time_1; + + date_time.date_time = GetSystemTime(); + date_time.update_tick = CoreTiming::GetTicks(); + date_time.tick_to_second_coefficient = g_clock_rate_arm11; + date_time.tick_offset = 0; + + ++shared_page.date_time_counter; + + // system time is updated hourly + CoreTiming::ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event); +} + void Init() { std::memset(&shared_page, 0, sizeof(shared_page)); @@ -19,6 +73,9 @@ void Init() { // Some games wait until this value becomes 0x1, before asking running_hw shared_page.unknown_value = 0x1; + + update_time_event = CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback); + CoreTiming::ScheduleEvent(0, update_time_event); } } // namespace diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h index 35a07c685..cd9246726 100644 --- a/src/core/hle/shared_page.h +++ b/src/core/hle/shared_page.h @@ -25,13 +25,14 @@ namespace SharedPage { struct DateTime { u64_le date_time; // 0 u64_le update_tick; // 8 - INSERT_PADDING_BYTES(0x20 - 0x10); // 10 + u64_le tick_to_second_coefficient; // 10 + u64_le tick_offset; // 18 }; static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); struct SharedPageDef { // Most of these names are taken from the 3dbrew page linked above. - u32_le date_time_selector; // 0 + u32_le date_time_counter; // 0 u8 running_hw; // 4 /// "Microcontroller hardware info" u8 mcu_hw_info; // 5 From d63a76f4ce47962d7f191f3d4911c12344c4d249 Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 20 Jul 2016 20:49:01 +0800 Subject: [PATCH 45/77] CoreTiming: avoid overflow --- src/core/core_timing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 64f5b06d9..3d8a7d0c0 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -26,7 +26,7 @@ extern int g_clock_rate_arm11; inline s64 msToCycles(int ms) { - return g_clock_rate_arm11 / 1000 * ms; + return (s64)g_clock_rate_arm11 / 1000 * ms; } inline s64 msToCycles(float ms) { From e09e6837208a5cda81c0eee233f301433201cb8b Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 23 Jul 2016 17:10:32 +0100 Subject: [PATCH 46/77] =?UTF-8?q?Remove=20the=20-msse4.1=20on=20=C2=ACMSVC?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option makes the generated binary crash with an illegal instruction when the target CPU doesn’t support the SSE4.1 extension (see #1968), with no noticeable performance increase compared to a generic build. --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a436b981..779eb8e50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,11 +66,6 @@ message(STATUS "Target architecture: ${ARCHITECTURE}") if (NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - - if (ARCHITECTURE_x86_64) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.1") - endif() else() # Silence "deprecation" warnings add_definitions(/D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /D_SCL_SECURE_NO_WARNINGS) From 7331b790217f9a3e86e5668cb134bd8f073ff289 Mon Sep 17 00:00:00 2001 From: Alexandre LittleWhite Laurent Date: Sat, 23 Jul 2016 19:37:12 +0200 Subject: [PATCH 47/77] Protection against a resize of size 0 --- src/common/emu_window.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp index 08270dd88..fd728c109 100644 --- a/src/common/emu_window.cpp +++ b/src/common/emu_window.cpp @@ -51,7 +51,6 @@ static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsi } std::tuple EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { - new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); @@ -92,9 +91,9 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { } EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) { - - ASSERT(width > 0); - ASSERT(height > 0); + // When hiding the widget, the function receives a size of 0 + if (width == 0) width = 1; + if (height == 0) height = 1; EmuWindow::FramebufferLayout res = { width, height, {}, {} }; From f8f67221334dc6c81755961e2cdd8b14ad0441ce Mon Sep 17 00:00:00 2001 From: Andy Tran Date: Tue, 26 Jul 2016 11:08:06 +1000 Subject: [PATCH 48/77] Travis Build: OS X Startup Crash Fix (#1962) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Travis: Mac OS X Build Fix Addresses the issue of the nightly builds crashing on OS X. In short, the changes needed were to rename the references within the binaries in order to make the app “self-contained”. * Travis: Mac OS X Terminal Launches citra with a terminal (instead of going straight for the QT application, skipping the debugging terminal). * Travis: Clean Up Lines * Travis: Fix of EOL Issue * Travis: Merge Fixes from Build Branch * Travis: Forward OS X Arguments * Travis: Forward OS X Arg x2 The issue is, is that sure “open citra-qt.app —args test” works, but drag and drop doesn’t! * Travis: Something needed to be escaped --- .travis-upload.sh | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/.travis-upload.sh b/.travis-upload.sh index 1ad8f5e5e..7838bf079 100755 --- a/.travis-upload.sh +++ b/.travis-upload.sh @@ -23,6 +23,97 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then # move SDL2 libs into folder for deployment dylibbundler -b -x "${REV_NAME}/citra" -cd -d "${REV_NAME}/libs" -p "@executable_path/libs/" + + # Make the changes to make the citra-qt app standalone (i.e. not dependent on the current brew installation). + # To do this, the absolute references to each and every QT framework must be re-written to point to the local frameworks + # (in the Contents/Frameworks folder). + # The "install_name_tool" is used to do so. + + # Coreutils is a hack to coerce Homebrew to point to the absolute Cellar path (symlink dereferenced). i.e: + # ls -l /usr/local/opt/qt5:: /usr/local/opt/qt5 -> ../Cellar/qt5/5.6.1-1 + # grealpath ../Cellar/qt5/5.6.1-1:: /usr/local/Cellar/qt5/5.6.1-1 + brew install coreutils + + REV_NAME_ALT=$REV_NAME/ + # grealpath is located in coreutils, there is no "realpath" for OS X :( + QT_BREWS_PATH=$(grealpath "$(brew --prefix qt5)") + BREW_PATH=$(brew --prefix) + QT_VERSION_NUM=5 + + $BREW_PATH/opt/qt5/bin/macdeployqt "${REV_NAME_ALT}citra-qt.app" \ + -executable="${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt" + + # These are the files that macdeployqt packed into Contents/Frameworks/ - we don't want those, so we replace them. + declare -a macos_libs=("QtCore" "QtWidgets" "QtGui" "QtOpenGL" "QtPrintSupport") + + for macos_lib in "${macos_libs[@]}" + do + SC_FRAMEWORK_PART=$macos_lib.framework/Versions/$QT_VERSION_NUM/$macos_lib + # Replace macdeployqt versions of the Frameworks with our own (from /usr/local/opt/qt5/lib/) + cp "$BREW_PATH/opt/qt5/lib/$SC_FRAMEWORK_PART" "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART" + + # Replace references within the embedded Framework files with "internal" versions. + for macos_lib2 in "${macos_libs[@]}" + do + # Since brew references both the non-symlinked and symlink paths of QT5, it needs to be duplicated. + # /usr/local/Cellar/qt5/5.6.1-1/lib and /usr/local/opt/qt5/lib both resolve to the same files. + # So the two lines below are effectively duplicates when resolved as a path, but as strings, they aren't. + RM_FRAMEWORK_PART=$macos_lib2.framework/Versions/$QT_VERSION_NUM/$macos_lib2 + install_name_tool -change \ + $QT_BREWS_PATH/lib/$RM_FRAMEWORK_PART \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART" + install_name_tool -change \ + "$BREW_PATH/opt/qt5/lib/$RM_FRAMEWORK_PART" \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART" + done + done + + # Handles `This application failed to start because it could not find or load the Qt platform plugin "cocoa"` + # Which manifests itself as: + # "Exception Type: EXC_CRASH (SIGABRT) | Exception Codes: 0x0000000000000000, 0x0000000000000000 | Exception Note: EXC_CORPSE_NOTIFY" + # There may be more dylibs needed to be fixed... + declare -a macos_plugins=("Plugins/platforms/libqcocoa.dylib") + + for macos_lib in "${macos_plugins[@]}" + do + install_name_tool -id @executable_path/../$macos_lib "${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib" + for macos_lib2 in "${macos_libs[@]}" + do + RM_FRAMEWORK_PART=$macos_lib2.framework/Versions/$QT_VERSION_NUM/$macos_lib2 + install_name_tool -change \ + $QT_BREWS_PATH/lib/$RM_FRAMEWORK_PART \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib" + install_name_tool -change \ + "$BREW_PATH/opt/qt5/lib/$RM_FRAMEWORK_PART" \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib" + done + done + + for macos_lib in "${macos_libs[@]}" + do + # Debugging info for Travis-CI + otool -L "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$macos_lib.framework/Versions/$QT_VERSION_NUM/$macos_lib" + done + + # Make the citra-qt.app application launch a debugging terminal. + # Store away the actual binary + mv ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt-bin + + cat > ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt < Date: Sun, 17 Jul 2016 11:55:52 +0100 Subject: [PATCH 49/77] dyncom: Fix translation of thumb REVSH --- src/core/arm/dyncom/arm_dyncom_thumb.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp index 29272fd5d..3576370d1 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + // We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding // ARM instruction, and using the existing ARM simulator. @@ -293,15 +295,22 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3 | (BIT(tinstr, 4) << 18); // enable bit } } else if ((tinstr & 0x0F00) == 0x0a00) { - static const u32 subset[3] = { + static const u32 subset[4] = { 0xE6BF0F30, // REV 0xE6BF0FB0, // REV16 + 0, // undefined 0xE6FF0FB0, // REVSH }; - *ainstr = subset[BITS(tinstr, 6, 7)] // base - | (BITS(tinstr, 0, 2) << 12) // Rd - | BITS(tinstr, 3, 5); // Rm + size_t subset_index = BITS(tinstr, 6, 7); + + if (subset_index == 2) { + valid = ThumbDecodeStatus::UNDEFINED; + } else { + *ainstr = subset[subset_index] // base + | (BITS(tinstr, 0, 2) << 12) // Rd + | BITS(tinstr, 3, 5); // Rm + } } else { static const u32 subset[4] = { 0xE92D0000, // STMDB sp!,{rlist} From 9a9e9dc375163090394e212a11e6f58379dc9a90 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 28 Jul 2016 21:47:31 +0200 Subject: [PATCH 50/77] Instead of segfaulting, log an error to remind the user to dump the shared font file --- src/core/hle/service/apt/apt.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 1e54a53dd..0c623d45f 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -70,6 +70,13 @@ void Initialize(Service::Interface* self) { void GetSharedFont(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + if (!shared_font_mem) { + LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); + cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); + cmd_buff[1] = -1; // TODO: Find the right error code + return; + } + // The shared font has to be relocated to the new address before being passed to the application. VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address); // The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base, From e91327c86a863b9419fd3695b2400a52336ec3b5 Mon Sep 17 00:00:00 2001 From: Anon Date: Fri, 29 Jul 2016 07:45:49 -0500 Subject: [PATCH 51/77] Input GUI: Add tab to remap controls (#1900) --- src/citra_qt/CMakeLists.txt | 3 + src/citra_qt/config.cpp | 9 +- src/citra_qt/config.h | 6 +- src/citra_qt/configure.ui | 8 +- src/citra_qt/configure_dialog.cpp | 1 + src/citra_qt/configure_input.cpp | 149 ++++++++ src/citra_qt/configure_input.h | 63 ++++ src/citra_qt/configure_input.ui | 593 ++++++++++++++++++++++++++++++ src/citra_qt/main.cpp | 1 + 9 files changed, 825 insertions(+), 8 deletions(-) create mode 100644 src/citra_qt/configure_input.cpp create mode 100644 src/citra_qt/configure_input.h create mode 100644 src/citra_qt/configure_input.ui diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 017b43871..4402ad995 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -23,6 +23,7 @@ set(SRCS configure_dialog.cpp configure_general.cpp configure_system.cpp + configure_input.cpp game_list.cpp hotkeys.cpp main.cpp @@ -54,6 +55,7 @@ set(HEADERS configure_dialog.h configure_general.h configure_system.h + configure_input.h game_list.h game_list_p.h hotkeys.h @@ -72,6 +74,7 @@ set(UIS configure_debug.ui configure_general.ui configure_system.ui + configure_input.ui hotkeys.ui main.ui ) diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index ba7edaff9..0e5f285c0 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -3,14 +3,11 @@ // Refer to the license.txt file included. #include -#include -#include #include "citra_qt/config.h" #include "citra_qt/ui_settings.h" #include "common/file_util.h" -#include "core/settings.h" Config::Config() { // TODO: Don't hardcode the path; let the frontend decide where to put the config files. @@ -21,7 +18,7 @@ Config::Config() { Reload(); } -static const std::array defaults = { +const std::array Config::defaults = { // directly mapped keys Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2, @@ -109,7 +106,7 @@ void Config::ReadValues() { UISettings::values.shortcuts.emplace_back( UISettings::Shortcut(group + "/" + hotkey, UISettings::ContextualShortcut(qt_config->value("KeySeq").toString(), - qt_config->value("Context").toInt()))); + qt_config->value("Context").toInt()))); qt_config->endGroup(); } @@ -191,7 +188,7 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Shortcuts"); - for (auto shortcut : UISettings::values.shortcuts ) { + for (auto shortcut : UISettings::values.shortcuts) { qt_config->setValue(shortcut.first + "/KeySeq", shortcut.second.first); qt_config->setValue(shortcut.first + "/Context", shortcut.second.second); } diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h index dd0b2ef0b..0cbdb707f 100644 --- a/src/citra_qt/config.h +++ b/src/citra_qt/config.h @@ -1,10 +1,13 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2014 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include +#include + +#include "core/settings.h" class QSettings; @@ -20,4 +23,5 @@ public: void Reload(); void Save(); + static const std::array defaults; }; diff --git a/src/citra_qt/configure.ui b/src/citra_qt/configure.ui index 4a9c52650..15fe17323 100644 --- a/src/citra_qt/configure.ui +++ b/src/citra_qt/configure.ui @@ -29,7 +29,7 @@ System
- + Input @@ -80,6 +80,12 @@
configure_debug.h
1 + + ConfigureInput + QWidget +
configure_input.h
+ 1 +
diff --git a/src/citra_qt/configure_dialog.cpp b/src/citra_qt/configure_dialog.cpp index 77c266d01..459fac4bb 100644 --- a/src/citra_qt/configure_dialog.cpp +++ b/src/citra_qt/configure_dialog.cpp @@ -30,6 +30,7 @@ void ConfigureDialog::setConfiguration() { void ConfigureDialog::applyConfiguration() { ui->generalTab->applyConfiguration(); ui->systemTab->applyConfiguration(); + ui->inputTab->applyConfiguration(); ui->audioTab->applyConfiguration(); ui->debugTab->applyConfiguration(); } diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp new file mode 100644 index 000000000..9c7a67174 --- /dev/null +++ b/src/citra_qt/configure_input.cpp @@ -0,0 +1,149 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include + +#include "citra_qt/configure_input.h" + +ConfigureInput::ConfigureInput(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { + ui->setupUi(this); + + // Initialize mapping of input enum to UI button. + input_mapping = { + { std::make_pair(Settings::NativeInput::Values::A, ui->buttonA) }, + { std::make_pair(Settings::NativeInput::Values::B, ui->buttonB) }, + { std::make_pair(Settings::NativeInput::Values::X, ui->buttonX) }, + { std::make_pair(Settings::NativeInput::Values::Y, ui->buttonY) }, + { std::make_pair(Settings::NativeInput::Values::L, ui->buttonL) }, + { std::make_pair(Settings::NativeInput::Values::R, ui->buttonR) }, + { std::make_pair(Settings::NativeInput::Values::ZL, ui->buttonZL) }, + { std::make_pair(Settings::NativeInput::Values::ZR, ui->buttonZR) }, + { std::make_pair(Settings::NativeInput::Values::START, ui->buttonStart) }, + { std::make_pair(Settings::NativeInput::Values::SELECT, ui->buttonSelect) }, + { std::make_pair(Settings::NativeInput::Values::HOME, ui->buttonHome) }, + { std::make_pair(Settings::NativeInput::Values::DUP, ui->buttonDpadUp) }, + { std::make_pair(Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown) }, + { std::make_pair(Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft) }, + { std::make_pair(Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight) }, + { std::make_pair(Settings::NativeInput::Values::CUP, ui->buttonCStickUp) }, + { std::make_pair(Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown) }, + { std::make_pair(Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft) }, + { std::make_pair(Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_MODIFIER, ui->buttonCircleMod) }, + }; + + // Attach handle click method to each button click. + for (const auto& entry : input_mapping) { + connect(entry.second, SIGNAL(released()), this, SLOT(handleClick())); + } + connect(ui->buttonRestoreDefaults, SIGNAL(released()), this, SLOT(restoreDefaults())); + setFocusPolicy(Qt::ClickFocus); + timer = new QTimer(this); + timer->setSingleShot(true); + connect(timer, &QTimer::timeout, this, [&]() { key_pressed = Qt::Key_Escape; setKey(); }); + this->setConfiguration(); +} + +void ConfigureInput::handleClick() { + QPushButton* sender = qobject_cast(QObject::sender()); + previous_mapping = sender->text(); + sender->setText(tr("[waiting]")); + sender->setFocus(); + grabKeyboard(); + grabMouse(); + changing_button = sender; + timer->start(5000); //Cancel after 5 seconds +} + +void ConfigureInput::applyConfiguration() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + int value = getKeyValue(input_mapping[Settings::NativeInput::Values(i)]->text()); + Settings::values.input_mappings[Settings::NativeInput::All[i]] = value; + } + Settings::Apply(); +} + +void ConfigureInput::setConfiguration() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + QString keyValue = getKeyName(Settings::values.input_mappings[i]); + input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue); + } +} + +void ConfigureInput::keyPressEvent(QKeyEvent* event) { + if (!changing_button) + return; + if (!event || event->key() == Qt::Key_unknown) + return; + key_pressed = event->key(); + timer->stop(); + setKey(); +} + +void ConfigureInput::setKey() { + const QString key_value = getKeyName(key_pressed); + if (key_pressed == Qt::Key_Escape) + changing_button->setText(previous_mapping); + else + changing_button->setText(key_value); + removeDuplicates(key_value); + key_pressed = Qt::Key_unknown; + releaseKeyboard(); + releaseMouse(); + changing_button = nullptr; + previous_mapping = nullptr; +} + +QString ConfigureInput::getKeyName(int key_code) const { + if (key_code == Qt::Key_Shift) + return tr("Shift"); + if (key_code == Qt::Key_Control) + return tr("Ctrl"); + if (key_code == Qt::Key_Alt) + return tr("Alt"); + if (key_code == Qt::Key_Meta) + return ""; + if (key_code == -1) + return ""; + + return QKeySequence(key_code).toString(); +} + +Qt::Key ConfigureInput::getKeyValue(const QString& text) const { + if (text == "Shift") + return Qt::Key_Shift; + if (text == "Ctrl") + return Qt::Key_Control; + if (text == "Alt") + return Qt::Key_Alt; + if (text == "Meta") + return Qt::Key_unknown; + if (text == "") + return Qt::Key_unknown; + + return Qt::Key(QKeySequence(text)[0]); +} + +void ConfigureInput::removeDuplicates(const QString& newValue) { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + if (changing_button != input_mapping[Settings::NativeInput::Values(i)]) { + const QString oldValue = input_mapping[Settings::NativeInput::Values(i)]->text(); + if (newValue == oldValue) + input_mapping[Settings::NativeInput::Values(i)]->setText(""); + } + } +} + +void ConfigureInput::restoreDefaults() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + const QString keyValue = getKeyName(Config::defaults[i].toInt()); + input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue); + } +} diff --git a/src/citra_qt/configure_input.h b/src/citra_qt/configure_input.h new file mode 100644 index 000000000..fe8ea5580 --- /dev/null +++ b/src/citra_qt/configure_input.h @@ -0,0 +1,63 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "citra_qt/config.h" +#include "core/settings.h" +#include "ui_configure_input.h" + +class QPushButton; +class QString; +class QTimer; + +namespace Ui { + class ConfigureInput; +} + +class ConfigureInput : public QWidget { + Q_OBJECT + +public: + explicit ConfigureInput(QWidget* parent = nullptr); + + /// Save all button configurations to settings file + void applyConfiguration(); + +private: + std::unique_ptr ui; + std::map input_mapping; + int key_pressed; + QPushButton* changing_button = nullptr; ///< button currently waiting for key press. + QString previous_mapping; + QTimer* timer; + + /// Load configuration settings into button text + void setConfiguration(); + + /// Check all inputs for duplicate keys. Clears out any other button with the same value as this button's new value. + void removeDuplicates(const QString& newValue); + + /// Handle key press event for input tab when a button is 'waiting'. + void keyPressEvent(QKeyEvent* event) override; + + /// Convert key ASCII value to its' letter/name + QString getKeyName(int key_code) const; + + /// Convert letter/name of key to its ASCII value. + Qt::Key getKeyValue(const QString& text) const; + + /// Set button text to name of key pressed. + void setKey(); + +private slots: + /// Event handler for all button released() event. + void handleClick(); + + /// Restore all buttons to their default values. + void restoreDefaults(); +}; diff --git a/src/citra_qt/configure_input.ui b/src/citra_qt/configure_input.ui new file mode 100644 index 000000000..a040d4df4 --- /dev/null +++ b/src/citra_qt/configure_input.ui @@ -0,0 +1,593 @@ + + + ConfigureInput + + + + 0 + 0 + 370 + 534 + + + + ConfigureInput + + + + + + + + Face Buttons + + + false + + + false + + + + + + + + A: + + + + + + + + + + + + + + + + + + B: + + + + + + + + + + + + + + + + + + X: + + + + + + + + + + + + + + + + + + Y: + + + + + + + + + + + + + + + + + + + Directional Pad + + + false + + + false + + + + + + + + Up: + + + + + + + + + + + + + + + + + + Down: + + + + + + + + + + + + + + + + + + Left: + + + + + + + + + + + + + + + + + + Right: + + + + + + + + + + + + + + + + + + + Shoulder Buttons + + + false + + + false + + + + + + + + L: + + + + + + + + + + + + + + + + + + R: + + + + + + + + + + + + + + + + + + ZL: + + + + + + + + + + + + + + + + + + ZR: + + + + + + + + + + + + + + + + + + + + Circle Pad + + + false + + + false + + + + + + + + Left: + + + + + + + + + + + + + + + + + + Right: + + + + + + + + + + + + + + + + + + Up: + + + + + + + + + + + + + + + + + + Down: + + + + + + + + + + + + + + + + + + + C-Stick + + + false + + + false + + + + + + + + Left: + + + + + + + + + + + + + + + + + + Right: + + + + + + + + + + + + + + + + + + Up: + + + + + + + + + + + + + + + + + + Down: + + + + + + + + + + + + + + + + + + + Misc. + + + false + + + false + + + + + + + + Start: + + + + + + + + + + + + + + + + + + Select: + + + + + + + + + + + + + + + + + + Home: + + + + + + + + + + + + + + + + + + Circle Mod: + + + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Restore Defaults + + + + + + + + + + diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 6fe5d7a3f..68a936087 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -513,6 +513,7 @@ void GMainWindow::OnConfigure() { if (result == QDialog::Accepted) { configureDialog.applyConfiguration(); + render_window->ReloadSetKeymaps(); config->Save(); } } From a94fb932ff8a326a2e85ab3814663af565313ec5 Mon Sep 17 00:00:00 2001 From: Lectem Date: Sat, 30 Jul 2016 18:19:00 +0200 Subject: [PATCH 52/77] fix #1942 and adds a few IPC functions for descriptors --- src/core/hle/kernel/session.h | 118 ++++++++++++++++++++++++++---- src/core/hle/service/apt/apt.cpp | 4 +- src/core/hle/service/cam/cam.cpp | 6 +- src/core/hle/service/csnd_snd.cpp | 2 +- src/core/hle/service/srv.cpp | 2 +- 5 files changed, 110 insertions(+), 22 deletions(-) diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 26b086f87..8ec889967 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -16,42 +16,130 @@ namespace IPC { -constexpr u32 MakeHeader(u16 command_id, unsigned int regular_params, unsigned int translate_params) { - return ((u32)command_id << 16) | (((u32)regular_params & 0x3F) << 6) | (((u32)translate_params & 0x3F) << 0); +enum DescriptorType : u32 { + // Buffer related desciptors types (mask : 0x0F) + StaticBuffer = 0x02, + PXIBuffer = 0x04, + MappedBuffer = 0x08, + // Handle related descriptors types (mask : 0x30, but need to check for buffer related descriptors first ) + CopyHandle = 0x00, + MoveHandle = 0x10, + CallingPid = 0x20, +}; + +/** + * @brief Creates a command header to be used for IPC + * @param command_id ID of the command to create a header for. + * @param normal_params Size of the normal parameters in words. Up to 63. + * @param translate_params_size Size of the translate parameters in words. Up to 63. + * @return The created IPC header. + * + * Normal parameters are sent directly to the process while the translate parameters might go through modifications and checks by the kernel. + * The translate parameters are described by headers generated with the IPC::*Desc functions. + * + * @note While #normal_params is equivalent to the number of normal parameters, #translate_params_size includes the size occupied by the translate parameters headers. + */ +constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, unsigned int translate_params_size) { + return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | (u32(translate_params_size) & 0x3F); } -constexpr u32 MoveHandleDesc(unsigned int num_handles = 1) { - return 0x0 | ((num_handles - 1) << 26); +union Header { + u32 raw; + BitField< 0, 6, u32> translate_params_size; + BitField< 6, 6, u32> normal_params; + BitField<16, 16, u32> command_id; +}; + +inline Header ParseHeader(u32 header) { + return{ header }; } -constexpr u32 CopyHandleDesc(unsigned int num_handles = 1) { - return 0x10 | ((num_handles - 1) << 26); +constexpr u32 MoveHandleDesc(u32 num_handles = 1) { + return MoveHandle | ((num_handles - 1) << 26); +} + +constexpr u32 CopyHandleDesc(u32 num_handles = 1) { + return CopyHandle | ((num_handles - 1) << 26); } constexpr u32 CallingPidDesc() { - return 0x20; + return CallingPid; } -constexpr u32 TransferHandleDesc() { - return 0x20; +constexpr bool isHandleDescriptor(u32 descriptor) { + return (descriptor & 0xF) == 0x0; } -constexpr u32 StaticBufferDesc(u32 size, unsigned int buffer_id) { - return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10); +constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) { + return (handle_descriptor >> 26) + 1; +} + +constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) { + return StaticBuffer | (size << 14) | ((buffer_id & 0xF) << 10); +} + +union StaticBufferDescInfo { + u32 raw; + BitField< 10, 4, u32> buffer_id; + BitField< 14, 18, u32> size; +}; + +inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { + return{ desc }; +} + +/** + * @brief Creates a header describing a buffer to be sent over PXI. + * @param size Size of the buffer. Max 0x00FFFFFF. + * @param buffer_id The Id of the buffer. Max 0xF. + * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have read-write access. + * @return The created PXI buffer header. + * + * The next value is a phys-address of a table located in the BASE memregion. + */ +inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { + u32 type = PXIBuffer; + if (is_read_only) type |= 0x2; + return type | (size << 8) | ((buffer_id & 0xF) << 4); } enum MappedBufferPermissions { - R = 2, - W = 4, + R = 1, + W = 2, RW = R | W, }; constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { - return 0x8 | (size << 4) | (u32)perms; + return MappedBuffer | (size << 4) | (u32(perms) << 1); } +union MappedBufferDescInfo { + u32 raw; + BitField< 4, 28, u32> size; + BitField< 1, 2, MappedBufferPermissions> perms; +}; + +inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { + return{ desc }; } +inline DescriptorType GetDescriptorType(u32 descriptor) { + // Note: Those checks must be done in this order + if (isHandleDescriptor(descriptor)) + return (DescriptorType)(descriptor & 0x30); + + // handle the fact that the following descriptors can have rights + if (descriptor & MappedBuffer) + return MappedBuffer; + + if (descriptor & PXIBuffer) + return PXIBuffer; + + return StaticBuffer; +} + +} // namespace IPC + namespace Kernel { static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header @@ -64,7 +152,7 @@ static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of * @param offset Optional offset into command buffer * @return Pointer to command buffer */ -inline static u32* GetCommandBuffer(const int offset = 0) { +inline u32* GetCommandBuffer(const int offset = 0) { return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset); } diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index c009e6c98..5af0d49ba 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -53,7 +53,7 @@ void Initialize(Service::Interface* self) { u32 app_id = cmd_buff[1]; u32 flags = cmd_buff[2]; - cmd_buff[2] = IPC::MoveHandleDesc(2); + cmd_buff[2] = IPC::CopyHandleDesc(2); cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom(); @@ -96,7 +96,7 @@ void GetSharedFont(Service::Interface* self) { // the real APT service calculates this address by scanning the entire address space (using svcQueryMemory) // and searches for an allocation of the same size as the Shared Font. cmd_buff[2] = target_address; - cmd_buff[3] = IPC::MoveHandleDesc(); + cmd_buff[3] = IPC::CopyHandleDesc(); cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); } diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp index 9df48a650..6edcf9610 100644 --- a/src/core/hle/service/cam/cam.cpp +++ b/src/core/hle/service/cam/cam.cpp @@ -51,7 +51,7 @@ void GetVsyncInterruptEvent(Service::Interface* self) { cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2); cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = IPC::MoveHandleDesc(); + cmd_buff[2] = IPC::CopyHandleDesc(); cmd_buff[3] = Kernel::g_handle_table.Create(vsync_interrupt_error_event).MoveFrom(); LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); @@ -64,7 +64,7 @@ void GetBufferErrorInterruptEvent(Service::Interface* self) { cmd_buff[0] = IPC::MakeHeader(0x6, 1, 2); cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = IPC::MoveHandleDesc(); + cmd_buff[2] = IPC::CopyHandleDesc(); cmd_buff[3] = Kernel::g_handle_table.Create(interrupt_error_event).MoveFrom(); LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); @@ -85,7 +85,7 @@ void SetReceiving(Service::Interface* self) { cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2); cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = IPC::MoveHandleDesc(); + cmd_buff[2] = IPC::CopyHandleDesc(); cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom(); LOG_WARNING(Service_CAM, "(STUBBED) called, addr=0x%X, port=%d, image_size=%d, trans_unit=%d", diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp index d2bb8941c..913c8dc09 100644 --- a/src/core/hle/service/csnd_snd.cpp +++ b/src/core/hle/service/csnd_snd.cpp @@ -51,7 +51,7 @@ void Initialize(Service::Interface* self) { mutex = Kernel::Mutex::Create(false); cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = IPC::MoveHandleDesc(2); + cmd_buff[2] = IPC::CopyHandleDesc(2); cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom(); cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom(); } diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 8bd36d5ea..3c05f836b 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -57,7 +57,7 @@ static void EnableNotification(Service::Interface* self) { cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = IPC::TransferHandleDesc(); + cmd_buff[2] = IPC::CopyHandleDesc(1); cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); LOG_WARNING(Service_SRV, "(STUBBED) called"); } From a976c2e3ba146df2fda9293c6fce9e11d96ac038 Mon Sep 17 00:00:00 2001 From: James Rowe Date: Thu, 30 Jun 2016 11:59:32 -0600 Subject: [PATCH 53/77] CMake: Fix for QT 5.7 overwriting -std=c++1y flag In QT 5.7 they added a new check for CXX features which appends a minimum required standard to the CXX_FLAGS. Because we were writing the flag directly previously, cmake assumed it needed to add a c++11 flag to the build. This tells cmake to use c++14 on every build. --- .travis-deps.sh | 4 ++-- CMakeLists.txt | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.travis-deps.sh b/.travis-deps.sh index 10b69f5c4..aad9074bf 100755 --- a/.travis-deps.sh +++ b/.travis-deps.sh @@ -9,7 +9,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then export CXX=g++-6 mkdir -p $HOME/.local - curl -L http://www.cmake.org/files/v3.1/cmake-3.1.0-Linux-i386.tar.gz \ + curl -L http://www.cmake.org/files/v3.2/cmake-3.2.0-Linux-i386.tar.gz \ | tar -xz -C $HOME/.local --strip-components=1 ( @@ -21,6 +21,6 @@ if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then elif [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update > /dev/null # silence the very verbose output brew unlink cmake - brew install cmake31 qt5 sdl2 dylibbundler + brew install cmake qt5 sdl2 dylibbundler gem install xcpretty fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 779eb8e50..4a271c36f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,5 @@ -# CMake 3.1 required for Qt5 settings to be applied automatically on -# dependent libraries and IMPORTED targets. -cmake_minimum_required(VERSION 3.1) +# CMake 3.2 required for cmake to know the right flags for CXX standard on OSX +cmake_minimum_required(VERSION 3.2) function(download_bundled_external remote_path lib_name prefix_var) set(prefix "${CMAKE_BINARY_DIR}/externals/${lib_name}") @@ -63,8 +62,11 @@ if (NOT DEFINED ARCHITECTURE) endif() message(STATUS "Target architecture: ${ARCHITECTURE}") +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + if (NOT MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") else() # Silence "deprecation" warnings From 50407a8dc86685d6f261680162823dfc44377285 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 14 Aug 2016 00:49:34 +0100 Subject: [PATCH 54/77] Dyncom: Correct implementation of STM for R15 --- src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 01d5d478e..6d5fb7aec 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -3228,7 +3228,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { addr += 4; } if (BIT(inst_cream->inst, 15)) { - cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8); + cpu->WriteMemory32(addr, cpu->Reg[15] + 8); } } else { for (int i = 0; i < 15; i++) { @@ -3243,8 +3243,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { } // Check PC reg - if (BIT(inst_cream->inst, 15)) - cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8); + if (BIT(inst_cream->inst, 15)) { + cpu->WriteMemory32(addr, cpu->Reg[15] + 8); + } } } cpu->Reg[15] += cpu->GetInstructionSize(); From 33d17d0b627bc193eed030b3926cb226dd08dfa0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 15 Aug 2016 22:52:15 -0400 Subject: [PATCH 55/77] qt: Use 5.7 on Windows. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a271c36f..6ac3df0e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,7 +181,7 @@ ENDIF (APPLE) if (ENABLE_QT) if (CITRA_USE_BUNDLED_QT) if (MSVC14 AND ARCHITECTURE_x86_64) - set(QT_VER qt-5.5-msvc2015_64) + set(QT_VER qt-5.7-msvc2015_64) else() message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.") endif() From 7b4dcacbb2006de6483e982b21956a8f3098aa1d Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 15 Aug 2016 23:30:02 -0400 Subject: [PATCH 56/77] citra: Default to HW renderer. --- src/citra/config.cpp | 2 +- src/citra/default_ini.h | 4 ++-- src/citra_qt/config.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 22cb51ea8..e832ec58d 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -68,7 +68,7 @@ void Config::ReadValues() { Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0); // Renderer - Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", false); + Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true); Settings::values.use_shader_jit = sdl2_config->GetBoolean("Renderer", "use_shader_jit", true); Settings::values.use_scaled_resolution = sdl2_config->GetBoolean("Renderer", "use_scaled_resolution", false); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 4e63f3206..6249ef9e2 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -44,11 +44,11 @@ frame_skip = [Renderer] # Whether to use software or hardware rendering. -# 0 (default): Software, 1: Hardware +# 0: Software, 1 (default): Hardware use_hw_renderer = # Whether to use the Just-In-Time (JIT) compiler for shader emulation -# 0 : Interpreter (slow), 1 (default): JIT (fast) +# 0: Interpreter (slow), 1 (default): JIT (fast) use_shader_jit = # Whether to use native 3DS screen resolution or to scale rendering resolution to the displayed screen size. diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 0e5f285c0..93c6a6e41 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -45,7 +45,7 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Renderer"); - Settings::values.use_hw_renderer = qt_config->value("use_hw_renderer", false).toBool(); + Settings::values.use_hw_renderer = qt_config->value("use_hw_renderer", true).toBool(); Settings::values.use_shader_jit = qt_config->value("use_shader_jit", true).toBool(); Settings::values.use_scaled_resolution = qt_config->value("use_scaled_resolution", false).toBool(); From 15b2eec4bdeadb6287a45c8d6fc77260280b45c8 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 22 Aug 2016 15:06:35 +0100 Subject: [PATCH 57/77] dyncom: Read-after-write in SMLA In the case when RD === RN, RD was updated before AddOverflow was called to check for an overflow, resulting in an incorrect state of the Q flag. --- src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 6d5fb7aec..c8d45c6db 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -2820,10 +2820,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); else operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); - RD = operand1 * operand2 + RN; - if (AddOverflow(operand1 * operand2, RN, RD)) + u32 product = operand1 * operand2; + u32 result = product + RN; + if (AddOverflow(product, RN, result)) cpu->Cpsr |= (1 << 27); + RD = result; } cpu->Reg[15] += cpu->GetInstructionSize(); INC_PC(sizeof(smla_inst)); From 15f16e256cf258e3e3bdb881001d7b649a7474e4 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Fri, 26 Aug 2016 16:18:01 +0100 Subject: [PATCH 58/77] .github: Add ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..4c9c7975a --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,25 @@ + \ No newline at end of file From 1f7ec4be9bf86f26d57555f7fd6b43851557e47d Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sat, 27 Aug 2016 01:04:26 -0700 Subject: [PATCH 59/77] Auto-detect original shared_font.bin memory base This allows a file dumped from either an o3DS or a n3DS (and potentially even an original unrebased file) to be used. --- src/core/hle/service/apt/apt.cpp | 7 +-- src/core/hle/service/apt/bcfnt/bcfnt.cpp | 79 +++++++++++++++++------- src/core/hle/service/apt/bcfnt/bcfnt.h | 12 +++- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index c009e6c98..4f4ee75cd 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -81,13 +81,8 @@ void GetSharedFont(Service::Interface* self) { // The shared font has to be relocated to the new address before being passed to the application. VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address); - // The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base, - // so we relocate it from there to our real address. - // TODO(Subv): This address is wrong if the shared font is dumped from a n3DS, - // we need a way to automatically calculate the original address of the font from the file. - static const VAddr SHARED_FONT_VADDR = 0x18000000; if (!shared_font_relocated) { - BCFNT::RelocateSharedFont(shared_font_mem, SHARED_FONT_VADDR, target_address); + BCFNT::RelocateSharedFont(shared_font_mem, target_address); shared_font_relocated = true; } cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.cpp b/src/core/hle/service/apt/bcfnt/bcfnt.cpp index b0d39d4a5..57eb39d75 100644 --- a/src/core/hle/service/apt/bcfnt/bcfnt.cpp +++ b/src/core/hle/service/apt/bcfnt/bcfnt.cpp @@ -9,60 +9,97 @@ namespace Service { namespace APT { namespace BCFNT { -void RelocateSharedFont(Kernel::SharedPtr shared_font, VAddr previous_address, VAddr new_address) { +void RelocateSharedFont(Kernel::SharedPtr shared_font, VAddr new_address) { static const u32 SharedFontStartOffset = 0x80; - u8* data = shared_font->GetPointer(SharedFontStartOffset); + const u8* cfnt_ptr = shared_font->GetPointer(SharedFontStartOffset); CFNT cfnt; - memcpy(&cfnt, data, sizeof(cfnt)); + memcpy(&cfnt, cfnt_ptr, sizeof(cfnt)); - // Advance past the header - data = shared_font->GetPointer(SharedFontStartOffset + cfnt.header_size); + u32 assumed_cmap_offset = 0; + u32 assumed_cwdh_offset = 0; + u32 assumed_tglp_offset = 0; + u32 first_cmap_offset = 0; + u32 first_cwdh_offset = 0; + u32 first_tglp_offset = 0; + // First discover the location of sections so that the rebase offset can be auto-detected + u32 current_offset = SharedFontStartOffset + cfnt.header_size; for (unsigned block = 0; block < cfnt.num_blocks; ++block) { + const u8* data = shared_font->GetPointer(current_offset); - u32 section_size = 0; - if (memcmp(data, "FINF", 4) == 0) { + SectionHeader section_header; + memcpy(§ion_header, data, sizeof(section_header)); + + if (first_cmap_offset == 0 && memcmp(section_header.magic, "CMAP", 4) == 0) { + first_cmap_offset = current_offset; + } else if (first_cwdh_offset == 0 && memcmp(section_header.magic, "CWDH", 4) == 0) { + first_cwdh_offset = current_offset; + } else if (first_tglp_offset == 0 && memcmp(section_header.magic, "TGLP", 4) == 0) { + first_tglp_offset = current_offset; + } else if (memcmp(section_header.magic, "FINF", 4) == 0) { + BCFNT::FINF finf; + memcpy(&finf, data, sizeof(finf)); + + assumed_cmap_offset = finf.cmap_offset - sizeof(SectionHeader); + assumed_cwdh_offset = finf.cwdh_offset - sizeof(SectionHeader); + assumed_tglp_offset = finf.tglp_offset - sizeof(SectionHeader); + } + + current_offset += section_header.section_size; + } + + u32 previous_base = assumed_cmap_offset - first_cmap_offset; + ASSERT(previous_base == assumed_cwdh_offset - first_cwdh_offset); + ASSERT(previous_base == assumed_tglp_offset - first_tglp_offset); + + u32 offset = new_address - previous_base; + + // Reset pointer back to start of sections and do the actual rebase + current_offset = SharedFontStartOffset + cfnt.header_size; + for (unsigned block = 0; block < cfnt.num_blocks; ++block) { + u8* data = shared_font->GetPointer(current_offset); + + SectionHeader section_header; + memcpy(§ion_header, data, sizeof(section_header)); + + if (memcmp(section_header.magic, "FINF", 4) == 0) { BCFNT::FINF finf; memcpy(&finf, data, sizeof(finf)); - section_size = finf.section_size; // Relocate the offsets in the FINF section - finf.cmap_offset += new_address - previous_address; - finf.cwdh_offset += new_address - previous_address; - finf.tglp_offset += new_address - previous_address; + finf.cmap_offset += offset; + finf.cwdh_offset += offset; + finf.tglp_offset += offset; memcpy(data, &finf, sizeof(finf)); - } else if (memcmp(data, "CMAP", 4) == 0) { + } else if (memcmp(section_header.magic, "CMAP", 4) == 0) { BCFNT::CMAP cmap; memcpy(&cmap, data, sizeof(cmap)); - section_size = cmap.section_size; // Relocate the offsets in the CMAP section - cmap.next_cmap_offset += new_address - previous_address; + cmap.next_cmap_offset += offset; memcpy(data, &cmap, sizeof(cmap)); - } else if (memcmp(data, "CWDH", 4) == 0) { + } else if (memcmp(section_header.magic, "CWDH", 4) == 0) { BCFNT::CWDH cwdh; memcpy(&cwdh, data, sizeof(cwdh)); - section_size = cwdh.section_size; // Relocate the offsets in the CWDH section - cwdh.next_cwdh_offset += new_address - previous_address; + cwdh.next_cwdh_offset += offset; memcpy(data, &cwdh, sizeof(cwdh)); - } else if (memcmp(data, "TGLP", 4) == 0) { + } else if (memcmp(section_header.magic, "TGLP", 4) == 0) { BCFNT::TGLP tglp; memcpy(&tglp, data, sizeof(tglp)); - section_size = tglp.section_size; // Relocate the offsets in the TGLP section - tglp.sheet_data_offset += new_address - previous_address; + tglp.sheet_data_offset += offset; memcpy(data, &tglp, sizeof(tglp)); } - data += section_size; + current_offset += section_header.section_size; } } diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.h b/src/core/hle/service/apt/bcfnt/bcfnt.h index 388c6bea0..8936dcf63 100644 --- a/src/core/hle/service/apt/bcfnt/bcfnt.h +++ b/src/core/hle/service/apt/bcfnt/bcfnt.h @@ -22,6 +22,11 @@ struct CFNT { u32_le num_blocks; }; +struct SectionHeader { + u8 magic[4]; + u32_le section_size; +}; + struct FINF { u8 magic[4]; u32_le section_size; @@ -75,12 +80,13 @@ struct CWDH { }; /** - * Relocates the internal addresses of the BCFNT Shared Font to the new base. + * Relocates the internal addresses of the BCFNT Shared Font to the new base. The current base will + * be auto-detected based on the file headers. + * * @param shared_font SharedMemory object that contains the Shared Font - * @param previous_address Previous address at which the offsets in the structure were based. * @param new_address New base for the offsets in the structure. */ -void RelocateSharedFont(Kernel::SharedPtr shared_font, VAddr previous_address, VAddr new_address); +void RelocateSharedFont(Kernel::SharedPtr shared_font, VAddr new_address); } // namespace BCFNT } // namespace APT From b2df959733ee65cbf705dbfbd05761a06929a6b6 Mon Sep 17 00:00:00 2001 From: wwylele Date: Mon, 27 Jun 2016 20:42:42 +0300 Subject: [PATCH 60/77] Memory: add ReadCString function --- src/core/memory.cpp | 14 ++++++++++++++ src/core/memory.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 8c9e5d46d..9aa8c4e5a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -280,6 +280,20 @@ u8* GetPointer(const VAddr vaddr) { return nullptr; } +std::string ReadCString(VAddr vaddr, std::size_t max_length) { + std::string string; + string.reserve(max_length); + for (std::size_t i = 0; i < max_length; ++i) { + char c = Read8(vaddr); + if (c == '\0') + break; + string.push_back(c); + ++vaddr; + } + string.shrink_to_fit(); + return string; +} + u8* GetPhysicalPointer(PAddr address) { // TODO(Subv): This call should not go through the application's memory mapping. return GetPointer(PhysicalToVirtualAddress(address)); diff --git a/src/core/memory.h b/src/core/memory.h index ae5588dee..cad845385 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/common_types.h" @@ -130,6 +131,8 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size); u8* GetPointer(VAddr virtual_address); +std::string ReadCString(VAddr virtual_address, std::size_t max_length); + /** * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical * address. This should be used by services to translate addresses for use by the hardware. From 2161f52661f9866161165db480594672307940ad Mon Sep 17 00:00:00 2001 From: wwylele Date: Mon, 27 Jun 2016 21:38:49 +0300 Subject: [PATCH 61/77] ARM: add ClearInstructionCache function --- src/core/arm/arm_interface.h | 3 +++ src/core/arm/dyncom/arm_dyncom.cpp | 6 ++++++ src/core/arm/dyncom/arm_dyncom.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index d8abe5aeb..de5e9c8fa 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -32,6 +32,9 @@ public: Run(1); } + /// Clear all instruction cache + virtual void ClearInstructionCache() = 0; + /** * Set the Program Counter to an address * @param addr Address to set PC to diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 13492a08b..ab77da965 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -12,6 +12,7 @@ #include "core/arm/dyncom/arm_dyncom.h" #include "core/arm/dyncom/arm_dyncom_interpreter.h" #include "core/arm/dyncom/arm_dyncom_run.h" +#include "core/arm/dyncom/arm_dyncom_trans.h" #include "core/core.h" #include "core/core_timing.h" @@ -23,6 +24,11 @@ ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { ARM_DynCom::~ARM_DynCom() { } +void ARM_DynCom::ClearInstructionCache() { + state->instruction_cache.clear(); + trans_cache_buf_top = 0; +} + void ARM_DynCom::SetPC(u32 pc) { state->Reg[15] = pc; } diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 3664fd728..e763abc24 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -21,6 +21,8 @@ public: ARM_DynCom(PrivilegeMode initial_mode); ~ARM_DynCom(); + void ClearInstructionCache() override; + void SetPC(u32 pc) override; u32 GetPC() const override; u32 GetReg(int index) const override; From 1c9612b79155de9538d4b71ff71938786adcea11 Mon Sep 17 00:00:00 2001 From: wwylele Date: Fri, 15 Jul 2016 09:17:01 +0300 Subject: [PATCH 62/77] LDR: Implement CRO --- src/core/CMakeLists.txt | 8 +- src/core/hle/service/ldr_ro.cpp | 96 -- src/core/hle/service/ldr_ro/cro_helper.cpp | 1477 +++++++++++++++++ src/core/hle/service/ldr_ro/cro_helper.h | 691 ++++++++ src/core/hle/service/ldr_ro/ldr_ro.cpp | 748 +++++++++ src/core/hle/service/{ => ldr_ro}/ldr_ro.h | 0 .../service/ldr_ro/memory_synchronizer.cpp | 46 + .../hle/service/ldr_ro/memory_synchronizer.h | 44 + src/core/hle/service/service.cpp | 2 +- 9 files changed, 3013 insertions(+), 99 deletions(-) delete mode 100644 src/core/hle/service/ldr_ro.cpp create mode 100644 src/core/hle/service/ldr_ro/cro_helper.cpp create mode 100644 src/core/hle/service/ldr_ro/cro_helper.h create mode 100644 src/core/hle/service/ldr_ro/ldr_ro.cpp rename src/core/hle/service/{ => ldr_ro}/ldr_ro.h (100%) create mode 100644 src/core/hle/service/ldr_ro/memory_synchronizer.cpp create mode 100644 src/core/hle/service/ldr_ro/memory_synchronizer.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0773339a9..174e9dc79 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -95,7 +95,9 @@ set(SRCS hle/service/ir/ir_rst.cpp hle/service/ir/ir_u.cpp hle/service/ir/ir_user.cpp - hle/service/ldr_ro.cpp + hle/service/ldr_ro/cro_helper.cpp + hle/service/ldr_ro/ldr_ro.cpp + hle/service/ldr_ro/memory_synchronizer.cpp hle/service/mic_u.cpp hle/service/ndm/ndm.cpp hle/service/ndm/ndm_u.cpp @@ -238,7 +240,9 @@ set(HEADERS hle/service/ir/ir_rst.h hle/service/ir/ir_u.h hle/service/ir/ir_user.h - hle/service/ldr_ro.h + hle/service/ldr_ro/cro_helper.h + hle/service/ldr_ro/ldr_ro.h + hle/service/ldr_ro/memory_synchronizer.h hle/service/mic_u.h hle/service/ndm/ndm.h hle/service/ndm/ndm_u.h diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp deleted file mode 100644 index ecec2ce32..000000000 --- a/src/core/hle/service/ldr_ro.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/common_types.h" -#include "common/logging/log.h" - -#include "core/hle/service/ldr_ro.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace LDR_RO - -namespace LDR_RO { - -/** - * LDR_RO::Initialize service function - * Inputs: - * 1 : CRS buffer pointer - * 2 : CRS Size - * 3 : Process memory address where the CRS will be mapped - * 4 : Value, must be zero - * 5 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void Initialize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 crs_buffer_ptr = cmd_buff[1]; - u32 crs_size = cmd_buff[2]; - u32 address = cmd_buff[3]; - u32 value = cmd_buff[4]; - u32 process = cmd_buff[5]; - - if (value != 0) { - LOG_ERROR(Service_LDR, "This value should be zero, but is actually %u!", value); - } - - // TODO(purpasmart96): Verify return header on HW - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - LOG_WARNING(Service_LDR, "(STUBBED) called. crs_buffer_ptr=0x%08X, crs_size=0x%08X, address=0x%08X, value=0x%08X, process=0x%08X", - crs_buffer_ptr, crs_size, address, value, process); -} - -/** - * LDR_RO::LoadCRR service function - * Inputs: - * 1 : CRS buffer pointer - * 2 : CRS Size - * 3 : Value, must be zero - * 4 : KProcess handle - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - */ -static void LoadCRR(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 crs_buffer_ptr = cmd_buff[1]; - u32 crs_size = cmd_buff[2]; - u32 value = cmd_buff[3]; - u32 process = cmd_buff[4]; - - if (value != 0) { - LOG_ERROR(Service_LDR, "This value should be zero, but is actually %u!", value); - } - - // TODO(purpasmart96): Verify return header on HW - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - LOG_WARNING(Service_LDR, "(STUBBED) called. crs_buffer_ptr=0x%08X, crs_size=0x%08X, value=0x%08X, process=0x%08X", - crs_buffer_ptr, crs_size, value, process); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x000100C2, Initialize, "Initialize"}, - {0x00020082, LoadCRR, "LoadCRR"}, - {0x00030042, nullptr, "UnloadCCR"}, - {0x000402C2, nullptr, "LoadExeCRO"}, - {0x000500C2, nullptr, "LoadCROSymbols"}, - {0x00060042, nullptr, "CRO_Load?"}, - {0x00070042, nullptr, "LoadCROSymbols"}, - {0x00080042, nullptr, "Shutdown"}, - {0x000902C2, nullptr, "LoadExeCRO_New?"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp new file mode 100644 index 000000000..3d2a613ee --- /dev/null +++ b/src/core/hle/service/ldr_ro/cro_helper.cpp @@ -0,0 +1,1477 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/alignment.h" +#include "common/logging/log.h" +#include "common/scope_exit.h" + +#include "core/hle/service/ldr_ro/cro_helper.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace LDR_RO + +namespace LDR_RO { + +static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F + ResultCode(static_cast(31), ErrorModule::RO, ErrorSummary::InvalidArgument, ErrorLevel::Usage); + +static ResultCode CROFormatError(u32 description) { + return ResultCode(static_cast(description), ErrorModule::RO, ErrorSummary::WrongArgument, ErrorLevel::Permanent); +} + +const std::array CROHelper::ENTRY_SIZE {{ + 1, // code + 1, // data + 1, // module name + sizeof(SegmentEntry), + sizeof(ExportNamedSymbolEntry), + sizeof(ExportIndexedSymbolEntry), + 1, // export strings + sizeof(ExportTreeEntry), + sizeof(ImportModuleEntry), + sizeof(ExternalRelocationEntry), + sizeof(ImportNamedSymbolEntry), + sizeof(ImportIndexedSymbolEntry), + sizeof(ImportAnonymousSymbolEntry), + 1, // import strings + sizeof(StaticAnonymousSymbolEntry), + sizeof(InternalRelocationEntry), + sizeof(StaticRelocationEntry) +}}; + +const std::array CROHelper::FIX_BARRIERS {{ + Fix0Barrier, + Fix1Barrier, + Fix2Barrier, + Fix3Barrier +}}; + +VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const { + u32 segment_num = GetField(SegmentNum); + + if (segment_tag.segment_index >= segment_num) + return 0; + + SegmentEntry entry; + GetEntry(segment_tag.segment_index, entry); + + if (segment_tag.offset_into_segment >= entry.size) + return 0; + + return entry.offset + segment_tag.offset_into_segment; +} + +ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType relocation_type, + u32 addend, u32 symbol_address, u32 target_future_address) { + + switch (relocation_type) { + case RelocationType::Nothing: + break; + case RelocationType::AbsoluteAddress: + case RelocationType::AbsoluteAddress2: + Memory::Write32(target_address, symbol_address + addend); + break; + case RelocationType::RelativeAddress: + Memory::Write32(target_address, symbol_address + addend - target_future_address); + break; + case RelocationType::ThumbBranch: + case RelocationType::ArmBranch: + case RelocationType::ModifyArmBranch: + case RelocationType::AlignedRelativeAddress: + // TODO(wwylele): implement other types + UNIMPLEMENTED(); + break; + default: + return CROFormatError(0x22); + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ClearRelocation(VAddr target_address, RelocationType relocation_type) { + switch (relocation_type) { + case RelocationType::Nothing: + break; + case RelocationType::AbsoluteAddress: + case RelocationType::AbsoluteAddress2: + case RelocationType::RelativeAddress: + Memory::Write32(target_address, 0); + break; + case RelocationType::ThumbBranch: + case RelocationType::ArmBranch: + case RelocationType::ModifyArmBranch: + case RelocationType::AlignedRelativeAddress: + // TODO(wwylele): implement other types + UNIMPLEMENTED(); + break; + default: + return CROFormatError(0x22); + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset) { + if (symbol_address == 0 && !reset) + return CROFormatError(0x10); + + VAddr relocation_address = batch; + while (true) { + RelocationEntry relocation; + Memory::ReadBlock(relocation_address, &relocation, sizeof(RelocationEntry)); + + VAddr relocation_target = SegmentTagToAddress(relocation.target_position); + if (relocation_target == 0) { + return CROFormatError(0x12); + } + + ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, symbol_address, relocation_target); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); + return result; + } + + if (relocation.is_batch_end) + break; + + relocation_address += sizeof(RelocationEntry); + } + + RelocationEntry relocation; + Memory::ReadBlock(batch, &relocation, sizeof(RelocationEntry)); + relocation.is_batch_resolved = reset ? 0 : 1; + Memory::WriteBlock(batch, &relocation, sizeof(RelocationEntry)); + return RESULT_SUCCESS; +} + +VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const { + if (!GetField(ExportTreeNum)) + return 0; + + std::size_t len = name.size(); + ExportTreeEntry entry; + GetEntry(0, entry); + ExportTreeEntry::Child next; + next.raw = entry.left.raw; + u32 found_id; + + while (true) { + GetEntry(next.next_index, entry); + + if (next.is_end) { + found_id = entry.export_table_index; + break; + } + + u16 test_byte = entry.test_bit >> 3; + u16 test_bit_in_byte = entry.test_bit & 7; + + if (test_byte >= len) { + next.raw = entry.left.raw; + } else if((name[test_byte] >> test_bit_in_byte) & 1) { + next.raw = entry.right.raw; + } else { + next.raw = entry.left.raw; + } + } + + u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); + + if (found_id >= export_named_symbol_num) + return 0; + + u32 export_strings_size = GetField(ExportStringsSize); + ExportNamedSymbolEntry symbol_entry; + GetEntry(found_id, symbol_entry); + + if (Memory::ReadCString(symbol_entry.name_offset, export_strings_size) != name) + return 0; + + return SegmentTagToAddress(symbol_entry.symbol_position); +} + +ResultCode CROHelper::RebaseHeader(u32 cro_size) { + ResultCode error = CROFormatError(0x11); + + // verifies magic + if (GetField(Magic) != MAGIC_CRO0) + return error; + + // verifies not registered + if (GetField(NextCRO) != 0 || GetField(PreviousCRO) != 0) + return error; + + // This seems to be a hard limit set by the RO module + if (GetField(FileSize) > 0x10000000 || GetField(BssSize) > 0x10000000) + return error; + + // verifies not fixed + if (GetField(FixedSize) != 0) + return error; + + if (GetField(CodeOffset) < CRO_HEADER_SIZE) + return error; + + // verifies that all offsets are in the correct order + constexpr std::array OFFSET_ORDER = {{ + CodeOffset, + ModuleNameOffset, + SegmentTableOffset, + ExportNamedSymbolTableOffset, + ExportTreeTableOffset, + ExportIndexedSymbolTableOffset, + ExportStringsOffset, + ImportModuleTableOffset, + ExternalRelocationTableOffset, + ImportNamedSymbolTableOffset, + ImportIndexedSymbolTableOffset, + ImportAnonymousSymbolTableOffset, + ImportStringsOffset, + StaticAnonymousSymbolTableOffset, + InternalRelocationTableOffset, + StaticRelocationTableOffset, + DataOffset, + FileSize + }}; + + u32 prev_offset = GetField(OFFSET_ORDER[0]); + u32 cur_offset; + for (std::size_t i = 1; i < OFFSET_ORDER.size(); ++i) { + cur_offset = GetField(OFFSET_ORDER[i]); + if (cur_offset < prev_offset) + return error; + prev_offset = cur_offset; + } + + // rebases offsets + u32 offset = GetField(NameOffset); + if (offset != 0) + SetField(NameOffset, offset + module_address); + + for (int field = CodeOffset; field < Fix0Barrier; field += 2) { + HeaderField header_field = static_cast(field); + offset = GetField(header_field); + if (offset != 0) + SetField(header_field, offset + module_address); + } + + // verifies everything is not beyond the buffer + u32 file_end = module_address + cro_size; + for (int field = CodeOffset, i = 0; field < Fix0Barrier; field += 2, ++i) { + HeaderField offset_field = static_cast(field); + HeaderField size_field = static_cast(field + 1); + if (GetField(offset_field) + GetField(size_field) * ENTRY_SIZE[i] > file_end) + return error; + } + + return RESULT_SUCCESS; +} + +ResultVal CROHelper::RebaseSegmentTable(u32 cro_size, + VAddr data_segment_address, u32 data_segment_size, + VAddr bss_segment_address, u32 bss_segment_size) { + + u32 prev_data_segment = 0; + u32 segment_num = GetField(SegmentNum); + for (u32 i = 0; i < segment_num; ++i) { + SegmentEntry segment; + GetEntry(i, segment); + if (segment.type == SegmentType::Data) { + if (segment.size != 0) { + if (segment.size > data_segment_size) + return ERROR_BUFFER_TOO_SMALL; + prev_data_segment = segment.offset; + segment.offset = data_segment_address; + } + } else if (segment.type == SegmentType::BSS) { + if (segment.size != 0) { + if (segment.size > bss_segment_size) + return ERROR_BUFFER_TOO_SMALL; + segment.offset = bss_segment_address; + } + } else if (segment.offset != 0) { + segment.offset += module_address; + if (segment.offset > module_address + cro_size) + return CROFormatError(0x19); + } + SetEntry(i, segment); + } + return MakeResult(prev_data_segment + module_address); +} + +ResultCode CROHelper::RebaseExportNamedSymbolTable() { + VAddr export_strings_offset = GetField(ExportStringsOffset); + VAddr export_strings_end = export_strings_offset + GetField(ExportStringsSize); + + u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); + for (u32 i = 0; i < export_named_symbol_num; ++i) { + ExportNamedSymbolEntry entry; + GetEntry(i, entry); + + if (entry.name_offset != 0) { + entry.name_offset += module_address; + if (entry.name_offset < export_strings_offset + || entry.name_offset >= export_strings_end) { + return CROFormatError(0x11); + } + } + + SetEntry(i, entry); + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::VerifyExportTreeTable() const { + u32 tree_num = GetField(ExportTreeNum); + for (u32 i = 0; i < tree_num; ++i) { + ExportTreeEntry entry; + GetEntry(i, entry); + + if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) { + return CROFormatError(0x11); + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::RebaseImportModuleTable() { + VAddr import_strings_offset = GetField(ImportStringsOffset); + VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize); + VAddr import_indexed_symbol_table_offset = GetField(ImportIndexedSymbolTableOffset); + VAddr index_import_table_end = import_indexed_symbol_table_offset + GetField(ImportIndexedSymbolNum) * sizeof(ImportIndexedSymbolEntry); + VAddr import_anonymous_symbol_table_offset = GetField(ImportAnonymousSymbolTableOffset); + VAddr offset_import_table_end = import_anonymous_symbol_table_offset + GetField(ImportAnonymousSymbolNum) * sizeof(ImportAnonymousSymbolEntry); + + u32 module_num = GetField(ImportModuleNum); + for (u32 i = 0; i < module_num; ++i) { + ImportModuleEntry entry; + GetEntry(i, entry); + + if (entry.name_offset != 0) { + entry.name_offset += module_address; + if (entry.name_offset < import_strings_offset + || entry.name_offset >= import_strings_end) { + return CROFormatError(0x18); + } + } + + if (entry.import_indexed_symbol_table_offset != 0) { + entry.import_indexed_symbol_table_offset += module_address; + if (entry.import_indexed_symbol_table_offset < import_indexed_symbol_table_offset + || entry.import_indexed_symbol_table_offset > index_import_table_end) { + return CROFormatError(0x18); + } + } + + if (entry.import_anonymous_symbol_table_offset != 0) { + entry.import_anonymous_symbol_table_offset += module_address; + if (entry.import_anonymous_symbol_table_offset < import_anonymous_symbol_table_offset + || entry.import_anonymous_symbol_table_offset > offset_import_table_end) { + return CROFormatError(0x18); + } + } + + SetEntry(i, entry); + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::RebaseImportNamedSymbolTable() { + VAddr import_strings_offset = GetField(ImportStringsOffset); + VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize); + VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); + VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); + + u32 num = GetField(ImportNamedSymbolNum); + for (u32 i = 0; i < num ; ++i) { + ImportNamedSymbolEntry entry; + GetEntry(i, entry); + + if (entry.name_offset != 0) { + entry.name_offset += module_address; + if (entry.name_offset < import_strings_offset + || entry.name_offset >= import_strings_end) { + return CROFormatError(0x1B); + } + } + + if (entry.relocation_batch_offset != 0) { + entry.relocation_batch_offset += module_address; + if (entry.relocation_batch_offset < external_relocation_table_offset + || entry.relocation_batch_offset > external_relocation_table_end) { + return CROFormatError(0x1B); + } + } + + SetEntry(i, entry); + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::RebaseImportIndexedSymbolTable() { + VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); + VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); + + u32 num = GetField(ImportIndexedSymbolNum); + for (u32 i = 0; i < num ; ++i) { + ImportIndexedSymbolEntry entry; + GetEntry(i, entry); + + if (entry.relocation_batch_offset != 0) { + entry.relocation_batch_offset += module_address; + if (entry.relocation_batch_offset < external_relocation_table_offset + || entry.relocation_batch_offset > external_relocation_table_end) { + return CROFormatError(0x14); + } + } + + SetEntry(i, entry); + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::RebaseImportAnonymousSymbolTable() { + VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); + VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); + + u32 num = GetField(ImportAnonymousSymbolNum); + for (u32 i = 0; i < num ; ++i) { + ImportAnonymousSymbolEntry entry; + GetEntry(i, entry); + + if (entry.relocation_batch_offset != 0) { + entry.relocation_batch_offset += module_address; + if (entry.relocation_batch_offset < external_relocation_table_offset + || entry.relocation_batch_offset > external_relocation_table_end) { + return CROFormatError(0x17); + } + } + + SetEntry(i, entry); + } + return RESULT_SUCCESS; +} + +VAddr CROHelper::GetOnUnresolvedAddress() { + return SegmentTagToAddress(SegmentTag(GetField(OnUnresolvedSegmentTag))); +} + +ResultCode CROHelper::ResetExternalRelocations() { + u32 unresolved_symbol = GetOnUnresolvedAddress(); + u32 external_relocation_num = GetField(ExternalRelocationNum); + ExternalRelocationEntry relocation; + + // Verifies that the last relocation is the end of a batch + GetEntry(external_relocation_num - 1, relocation); + if (!relocation.is_batch_end) { + return CROFormatError(0x12); + } + + bool batch_begin = true; + for (u32 i = 0; i < external_relocation_num; ++i) { + GetEntry(i, relocation); + VAddr relocation_target = SegmentTagToAddress(relocation.target_position); + + if (relocation_target == 0) { + return CROFormatError(0x12); + } + + ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, unresolved_symbol, relocation_target); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); + return result; + } + + if (batch_begin) { + // resets to unresolved state + relocation.is_batch_resolved = 0; + SetEntry(i, relocation); + } + + // if current is an end, then the next is a beginning + batch_begin = relocation.is_batch_end != 0; + } + + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ClearExternalRelocations() { + u32 external_relocation_num = GetField(ExternalRelocationNum); + ExternalRelocationEntry relocation; + + bool batch_begin = true; + for (u32 i = 0; i < external_relocation_num; ++i) { + GetEntry(i, relocation); + VAddr relocation_target = SegmentTagToAddress(relocation.target_position); + + if (relocation_target == 0) { + return CROFormatError(0x12); + } + + ResultCode result = ClearRelocation(relocation_target, relocation.type); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw); + return result; + } + + if (batch_begin) { + // resets to unresolved state + relocation.is_batch_resolved = 0; + SetEntry(i, relocation); + } + + // if current is an end, then the next is a beginning + batch_begin = relocation.is_batch_end != 0; + } + + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) { + VAddr static_relocation_table_offset = GetField(StaticRelocationTableOffset); + VAddr static_relocation_table_end = static_relocation_table_offset + GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry); + + CROHelper crs(crs_address); + u32 offset_export_num = GetField(StaticAnonymousSymbolNum); + LOG_INFO(Service_LDR, "CRO \"%s\" exports %d static anonymous symbols", ModuleName().data(), offset_export_num); + for (u32 i = 0; i < offset_export_num; ++i) { + StaticAnonymousSymbolEntry entry; + GetEntry(i, entry); + u32 batch_address = entry.relocation_batch_offset + module_address; + + if (batch_address < static_relocation_table_offset + || batch_address > static_relocation_table_end) { + return CROFormatError(0x16); + } + + u32 symbol_address = SegmentTagToAddress(entry.symbol_position); + LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module", ModuleName().data(), symbol_address); + ResultCode result = crs.ApplyRelocationBatch(batch_address, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) { + u32 segment_num = GetField(SegmentNum); + u32 internal_relocation_num = GetField(InternalRelocationNum); + for (u32 i = 0; i < internal_relocation_num; ++i) { + InternalRelocationEntry relocation; + GetEntry(i, relocation); + VAddr target_addressB = SegmentTagToAddress(relocation.target_position); + if (target_addressB == 0) { + return CROFormatError(0x15); + } + + VAddr target_address; + SegmentEntry target_segment; + GetEntry(relocation.target_position.segment_index, target_segment); + + if (target_segment.type == SegmentType::Data) { + // If the relocation is to the .data segment, we need to relocate it in the old buffer + target_address = old_data_segment_address + relocation.target_position.offset_into_segment; + } else { + target_address = target_addressB; + } + + if (relocation.symbol_segment >= segment_num) { + return CROFormatError(0x15); + } + + SegmentEntry symbol_segment; + GetEntry(relocation.symbol_segment, symbol_segment); + LOG_TRACE(Service_LDR, "Internally relocates 0x%08X with 0x%08X", target_address, symbol_segment.offset); + ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend, symbol_segment.offset, target_addressB); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); + return result; + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ClearInternalRelocations() { + u32 internal_relocation_num = GetField(InternalRelocationNum); + for (u32 i = 0; i < internal_relocation_num; ++i) { + InternalRelocationEntry relocation; + GetEntry(i, relocation); + VAddr target_address = SegmentTagToAddress(relocation.target_position); + + if (target_address == 0) { + return CROFormatError(0x15); + } + + ResultCode result = ClearRelocation(target_address, relocation.type); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw); + return result; + } + } + return RESULT_SUCCESS; +} + +void CROHelper::UnrebaseImportAnonymousSymbolTable() { + u32 num = GetField(ImportAnonymousSymbolNum); + for (u32 i = 0; i < num; ++i) { + ImportAnonymousSymbolEntry entry; + GetEntry(i, entry); + + if (entry.relocation_batch_offset != 0) { + entry.relocation_batch_offset -= module_address; + } + + SetEntry(i, entry); + } +} + +void CROHelper::UnrebaseImportIndexedSymbolTable() { + u32 num = GetField(ImportIndexedSymbolNum); + for (u32 i = 0; i < num; ++i) { + ImportIndexedSymbolEntry entry; + GetEntry(i, entry); + + if (entry.relocation_batch_offset != 0) { + entry.relocation_batch_offset -= module_address; + } + + SetEntry(i, entry); + } +} + +void CROHelper::UnrebaseImportNamedSymbolTable() { + u32 num = GetField(ImportNamedSymbolNum); + for (u32 i = 0; i < num; ++i) { + ImportNamedSymbolEntry entry; + GetEntry(i, entry); + + if (entry.name_offset != 0) { + entry.name_offset -= module_address; + } + + if (entry.relocation_batch_offset) { + entry.relocation_batch_offset -= module_address; + } + + SetEntry(i, entry); + } +} + +void CROHelper::UnrebaseImportModuleTable() { + u32 module_num = GetField(ImportModuleNum); + for (u32 i = 0; i < module_num; ++i) { + ImportModuleEntry entry; + GetEntry(i, entry); + + if (entry.name_offset != 0) { + entry.name_offset -= module_address; + } + + if (entry.import_indexed_symbol_table_offset) { + entry.import_indexed_symbol_table_offset -= module_address; + } + + if (entry.import_anonymous_symbol_table_offset) { + entry.import_anonymous_symbol_table_offset -= module_address; + } + + SetEntry(i, entry); + } +} + +void CROHelper::UnrebaseExportNamedSymbolTable() { + u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); + for (u32 i = 0; i < export_named_symbol_num; ++i) { + ExportNamedSymbolEntry entry; + GetEntry(i, entry); + + if (entry.name_offset != 0) { + entry.name_offset -= module_address; + } + + SetEntry(i, entry); + } +} + +void CROHelper::UnrebaseSegmentTable() { + u32 segment_num = GetField(SegmentNum); + for (u32 i = 0; i < segment_num; ++i) { + SegmentEntry segment; + GetEntry(i, segment); + + if (segment.type == SegmentType::BSS) { + segment.offset = 0; + } else if (segment.offset != 0) { + segment.offset -= module_address; + } + + SetEntry(i, segment); + } +} + +void CROHelper::UnrebaseHeader() { + u32 offset = GetField(NameOffset); + if (offset != 0) + SetField(NameOffset, offset - module_address); + + for (int field = CodeOffset; field < Fix0Barrier; field += 2) { + HeaderField header_field = static_cast(field); + offset = GetField(header_field); + if (offset != 0) + SetField(header_field, offset - module_address); + } +} + +ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) { + u32 import_strings_size = GetField(ImportStringsSize); + u32 symbol_import_num = GetField(ImportNamedSymbolNum); + for (u32 i = 0; i < symbol_import_num; ++i) { + ImportNamedSymbolEntry entry; + GetEntry(i, entry); + VAddr relocation_addr = entry.relocation_batch_offset; + ExternalRelocationEntry relocation_entry; + Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); + + if (!relocation_entry.is_batch_resolved) { + ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal { + std::string symbol_name = Memory::ReadCString(entry.name_offset, import_strings_size); + u32 symbol_address = source.FindExportNamedSymbol(symbol_name); + + if (symbol_address != 0) { + LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"", + ModuleName().data(), symbol_name.data(), source.ModuleName().data()); + + ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + + return MakeResult(false); + } + + return MakeResult(true); + }); + if (result.IsError()) { + return result; + } + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ResetImportNamedSymbol() { + u32 unresolved_symbol = GetOnUnresolvedAddress(); + + u32 symbol_import_num = GetField(ImportNamedSymbolNum); + for (u32 i = 0; i < symbol_import_num; ++i) { + ImportNamedSymbolEntry entry; + GetEntry(i, entry); + VAddr relocation_addr = entry.relocation_batch_offset; + ExternalRelocationEntry relocation_entry; + Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); + + ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); + return result; + } + + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ResetImportIndexedSymbol() { + u32 unresolved_symbol = GetOnUnresolvedAddress(); + + u32 import_num = GetField(ImportIndexedSymbolNum); + for (u32 i = 0; i < import_num; ++i) { + ImportIndexedSymbolEntry entry; + GetEntry(i, entry); + VAddr relocation_addr = entry.relocation_batch_offset; + ExternalRelocationEntry relocation_entry; + Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); + + ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); + return result; + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ResetImportAnonymousSymbol() { + u32 unresolved_symbol = GetOnUnresolvedAddress(); + + u32 import_num = GetField(ImportAnonymousSymbolNum); + for (u32 i = 0; i < import_num; ++i) { + ImportAnonymousSymbolEntry entry; + GetEntry(i, entry); + VAddr relocation_addr = entry.relocation_batch_offset; + ExternalRelocationEntry relocation_entry; + Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); + + ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); + return result; + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) { + u32 import_strings_size = GetField(ImportStringsSize); + + u32 import_module_num = GetField(ImportModuleNum); + for (u32 i = 0; i < import_module_num; ++i) { + ImportModuleEntry entry; + GetEntry(i, entry); + std::string want_cro_name = Memory::ReadCString(entry.name_offset, import_strings_size); + + ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal { + if (want_cro_name == source.ModuleName()) { + LOG_INFO(Service_LDR, "CRO \"%s\" imports %d indexed symbols from \"%s\"", + ModuleName().data(), entry.import_indexed_symbol_num, source.ModuleName().data()); + for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { + ImportIndexedSymbolEntry im; + entry.GetImportIndexedSymbolEntry(j, im); + ExportIndexedSymbolEntry ex; + source.GetEntry(im.index, ex); + u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position); + LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address); + ResultCode result = ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + LOG_INFO(Service_LDR, "CRO \"%s\" imports %d anonymous symbols from \"%s\"", + ModuleName().data(), entry.import_anonymous_symbol_num, source.ModuleName().data()); + for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { + ImportAnonymousSymbolEntry im; + entry.GetImportAnonymousSymbolEntry(j, im); + u32 symbol_address = source.SegmentTagToAddress(im.symbol_position); + LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address); + ResultCode result = ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + return MakeResult(false); + } + return MakeResult(true); + }); + if (result.IsError()) { + return result; + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) { + LOG_DEBUG(Service_LDR, "CRO \"%s\" exports named symbols to \"%s\"", + ModuleName().data(), target.ModuleName().data()); + u32 target_import_strings_size = target.GetField(ImportStringsSize); + u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum); + for (u32 i = 0; i < target_symbol_import_num; ++i) { + ImportNamedSymbolEntry entry; + target.GetEntry(i, entry); + VAddr relocation_addr = entry.relocation_batch_offset; + ExternalRelocationEntry relocation_entry; + Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); + + if (!relocation_entry.is_batch_resolved) { + std::string symbol_name = Memory::ReadCString(entry.name_offset, target_import_strings_size); + u32 symbol_address = FindExportNamedSymbol(symbol_name); + if (symbol_address != 0) { + LOG_TRACE(Service_LDR, " exports symbol \"%s\"", symbol_name.data()); + ResultCode result = target.ApplyRelocationBatch(relocation_addr, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) { + LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports named symbols to \"%s\"", + ModuleName().data(), target.ModuleName().data()); + u32 unresolved_symbol = target.GetOnUnresolvedAddress(); + u32 target_import_strings_size = target.GetField(ImportStringsSize); + u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum); + for (u32 i = 0; i < target_symbol_import_num; ++i) { + ImportNamedSymbolEntry entry; + target.GetEntry(i, entry); + VAddr relocation_addr = entry.relocation_batch_offset; + ExternalRelocationEntry relocation_entry; + Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); + + if (relocation_entry.is_batch_resolved) { + std::string symbol_name = Memory::ReadCString(entry.name_offset, target_import_strings_size); + u32 symbol_address = FindExportNamedSymbol(symbol_name); + if (symbol_address != 0) { + LOG_TRACE(Service_LDR, " unexports symbol \"%s\"", symbol_name.data()); + ResultCode result = target.ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + } + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ApplyModuleExport(CROHelper target) { + std::string module_name = ModuleName(); + u32 target_import_string_size = target.GetField(ImportStringsSize); + u32 target_import_module_num = target.GetField(ImportModuleNum); + for (u32 i = 0; i < target_import_module_num; ++i) { + ImportModuleEntry entry; + target.GetEntry(i, entry); + + if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name) + continue; + + LOG_INFO(Service_LDR, "CRO \"%s\" exports %d indexed symbols to \"%s\"", + module_name.data(), entry.import_indexed_symbol_num, target.ModuleName().data()); + for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { + ImportIndexedSymbolEntry im; + entry.GetImportIndexedSymbolEntry(j, im); + ExportIndexedSymbolEntry ex; + GetEntry(im.index, ex); + u32 symbol_address = SegmentTagToAddress(ex.symbol_position); + LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address); + ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + + LOG_INFO(Service_LDR, "CRO \"%s\" exports %d anonymous symbols to \"%s\"", + module_name.data(), entry.import_anonymous_symbol_num, target.ModuleName().data()); + for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { + ImportAnonymousSymbolEntry im; + entry.GetImportAnonymousSymbolEntry(j, im); + u32 symbol_address = SegmentTagToAddress(im.symbol_position); + LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address); + ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + } + + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ResetModuleExport(CROHelper target) { + u32 unresolved_symbol = target.GetOnUnresolvedAddress(); + + std::string module_name = ModuleName(); + u32 target_import_string_size = target.GetField(ImportStringsSize); + u32 target_import_module_num = target.GetField(ImportModuleNum); + for (u32 i = 0; i < target_import_module_num; ++i) { + ImportModuleEntry entry; + target.GetEntry(i, entry); + + if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name) + continue; + + LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports indexed symbols to \"%s\"", + module_name.data(), target.ModuleName().data()); + for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { + ImportIndexedSymbolEntry im; + entry.GetImportIndexedSymbolEntry(j, im); + ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + + LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports anonymous symbols to \"%s\"", + module_name.data(), target.ModuleName().data()); + for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { + ImportAnonymousSymbolEntry im; + entry.GetImportAnonymousSymbolEntry(j, im); + ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + } + } + + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) { + u32 import_strings_size = GetField(ImportStringsSize); + u32 symbol_import_num = GetField(ImportNamedSymbolNum); + for (u32 i = 0; i < symbol_import_num; ++i) { + ImportNamedSymbolEntry entry; + GetEntry(i, entry); + VAddr relocation_addr = entry.relocation_batch_offset; + ExternalRelocationEntry relocation_entry; + Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); + + if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit"){ + ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal { + u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_"); + + if (symbol_address != 0) { + LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"", + ModuleName().data(), source.ModuleName().data()); + + ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); + return result; + } + + return MakeResult(false); + } + + return MakeResult(true); + }); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying exit relocation %08X", result.raw); + return result; + } + } + } + return RESULT_SUCCESS; +} + +/** + * Verifies a string or a string table matching a predicted size (i.e. terminated by 0) + * if it is not empty. There can be many other nulls in the string table because + * they are composed by many sub strings. This function is to check whether the + * whole string (table) is terminated properly, despite that it is not actually one string. + * @param address the virtual address of the string (table) + * @param size the size of the string (table), including the terminating 0 + * @returns ResultCode RESULT_SUCCESS if the size matches, otherwise error code. + */ +static ResultCode VerifyStringTableLength(VAddr address, u32 size) { + if (size != 0) { + if (Memory::Read8(address + size - 1) != 0) + return CROFormatError(0x0B); + } + return RESULT_SUCCESS; +} + +ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, + VAddr data_segment_addresss, u32 data_segment_size, + VAddr bss_segment_address, u32 bss_segment_size, bool is_crs) { + + ResultCode result = RebaseHeader(cro_size); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing header %08X", result.raw); + return result; + } + + result = VerifyStringTableLength(GetField(ModuleNameOffset), GetField(ModuleNameSize)); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error verifying module name %08X", result.raw); + return result; + } + + u32 prev_data_segment_address = 0; + if (!is_crs) { + auto result_val = RebaseSegmentTable(cro_size, + data_segment_addresss, data_segment_size, + bss_segment_address, bss_segment_size); + if (result_val.Failed()) { + LOG_ERROR(Service_LDR, "Error rebasing segment table %08X", result_val.Code().raw); + return result_val.Code(); + } + prev_data_segment_address = *result_val; + } + + result = RebaseExportNamedSymbolTable(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing symbol export table %08X", result.raw); + return result; + } + + result = VerifyExportTreeTable(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error verifying export tree %08X", result.raw); + return result; + } + + result = VerifyStringTableLength(GetField(ExportStringsOffset), GetField(ExportStringsSize)); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error verifying export strings %08X", result.raw); + return result; + } + + result = RebaseImportModuleTable(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing object table %08X", result.raw); + return result; + } + + result = ResetExternalRelocations(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error resetting all external relocations %08X", result.raw); + return result; + } + + result = RebaseImportNamedSymbolTable(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing symbol import table %08X", result.raw); + return result; + } + + result = RebaseImportIndexedSymbolTable(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing index import table %08X", result.raw); + return result; + } + + result = RebaseImportAnonymousSymbolTable(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing offset import table %08X", result.raw); + return result; + } + + result = VerifyStringTableLength(GetField(ImportStringsOffset), GetField(ImportStringsSize)); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error verifying import strings %08X", result.raw); + return result; + } + + if (!is_crs) { + result = ApplyStaticAnonymousSymbolToCRS(crs_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying offset export to CRS %08X", result.raw); + return result; + } + } + + result = ApplyInternalRelocations(prev_data_segment_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying internal relocations %08X", result.raw); + return result; + } + + if (!is_crs) { + result = ApplyExitRelocations(crs_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying exit relocations %08X", result.raw); + return result; + } + } + + return RESULT_SUCCESS; +} + +void CROHelper::Unrebase(bool is_crs) { + UnrebaseImportAnonymousSymbolTable(); + UnrebaseImportIndexedSymbolTable(); + UnrebaseImportNamedSymbolTable(); + UnrebaseImportModuleTable(); + UnrebaseExportNamedSymbolTable(); + + if (!is_crs) + UnrebaseSegmentTable(); + + SetNextModule(0); + SetPreviousModule(0); + + SetField(FixedSize, 0); + + UnrebaseHeader(); +} + +ResultCode CROHelper::VerifyHash(u32 cro_size, VAddr crr) const { + // TODO(wwylele): actually verify the hash + return RESULT_SUCCESS; +} + +ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) { + ResultCode result = RESULT_SUCCESS; + + { + VAddr data_segment_address; + if (link_on_load_bug_fix) { + // this is a bug fix introduced by 7.2.0-17's LoadCRO_New + // The bug itself is: + // If a relocation target is in .data segment, it will relocate to the + // user-specified buffer. But if this is linking during loading, + // the .data segment hasn't been tranfer from CRO to the buffer, + // thus the relocation will be overwritten by data transfer. + // To fix this bug, we need temporarily restore the old .data segment + // offset and apply imported symbols. + + // RO service seems assuming segment_index == segment_type, + // so we do the same + if (GetField(SegmentNum) >= 2) { // means we have .data segment + SegmentEntry entry; + GetEntry(2, entry); + ASSERT(entry.type == SegmentType::Data); + data_segment_address = entry.offset; + entry.offset = GetField(DataOffset); + SetEntry(2, entry); + } + } + SCOPE_EXIT({ + // Restore the new .data segment address after importing + if (link_on_load_bug_fix) { + if (GetField(SegmentNum) >= 2) { + SegmentEntry entry; + GetEntry(2, entry); + entry.offset = data_segment_address; + SetEntry(2, entry); + } + } + }); + + // Imports named symbols from other modules + result = ApplyImportNamedSymbol(crs_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying symbol import %08X", result.raw); + return result; + } + + // Imports indexed and anonymous symbols from other modules + result = ApplyModuleImport(crs_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying module import %08X", result.raw); + return result; + } + } + + // Exports symbols to other modules + result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal { + ResultCode result = ApplyExportNamedSymbol(target); + if (result.IsError()) + return result; + + result = ApplyModuleExport(target); + if (result.IsError()) + return result; + + return MakeResult(true); + }); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error applying export %08X", result.raw); + return result; + } + + return RESULT_SUCCESS; +} + +ResultCode CROHelper::Unlink(VAddr crs_address) { + + // Resets all imported named symbols + ResultCode result = ResetImportNamedSymbol(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error resetting symbol import %08X", result.raw); + return result; + } + + // Resets all imported indexed symbols + result = ResetImportIndexedSymbol(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error resetting indexed import %08X", result.raw); + return result; + } + + // Resets all imported anonymous symbols + result = ResetImportAnonymousSymbol(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error resetting anonymous import %08X", result.raw); + return result; + } + + // Resets all symbols in other modules imported from this module + // Note: the RO service seems only searching in auto-link modules + result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal { + ResultCode result = ResetExportNamedSymbol(target); + if (result.IsError()) + return result; + + result = ResetModuleExport(target); + if (result.IsError()) + return result; + + return MakeResult(true); + }); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error resetting export %08X", result.raw); + return result; + } + + return RESULT_SUCCESS; +} + +ResultCode CROHelper::ClearRelocations() { + ResultCode result = ClearExternalRelocations(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error clearing external relocations %08X", result.raw); + return result; + } + + result = ClearInternalRelocations(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error clearing internal relocations %08X", result.raw); + return result; + } + return RESULT_SUCCESS; +} + +void CROHelper::InitCRS() { + SetNextModule(0); + SetPreviousModule(0); +} + +void CROHelper::Register(VAddr crs_address, bool auto_link) { + CROHelper crs(crs_address); + CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule()); + + if (head.module_address) { + // there are already CROs registered + // register as the new tail + CROHelper tail(head.PreviousModule()); + + // link with the old tail + ASSERT(tail.NextModule() == 0); + SetPreviousModule(tail.module_address); + tail.SetNextModule(module_address); + + // set previous of the head pointing to the new tail + head.SetPreviousModule(module_address); + } else { + // register as the first CRO + // set previous to self as tail + SetPreviousModule(module_address); + + // set self as head + if (auto_link) + crs.SetNextModule(module_address); + else + crs.SetPreviousModule(module_address); + } + + // the new one is the tail + SetNextModule(0); +} + +void CROHelper::Unregister(VAddr crs_address) { + CROHelper crs(crs_address); + CROHelper next_head(crs.NextModule()), previous_head(crs.PreviousModule()); + CROHelper next(NextModule()), previous(PreviousModule()); + + if (module_address == next_head.module_address || module_address == previous_head.module_address) { + // removing head + if (next.module_address) { + // the next is new head + // let its previous point to the tail + next.SetPreviousModule(previous.module_address); + } + + // set new head + if (module_address == previous_head.module_address) { + crs.SetPreviousModule(next.module_address); + } else { + crs.SetNextModule(next.module_address); + } + } else if (next.module_address) { + // link previous and next + previous.SetNextModule(next.module_address); + next.SetPreviousModule(previous.module_address); + } else { + // removing tail + // set previous as new tail + previous.SetNextModule(0); + + // let head's previous point to the new tail + if (next_head.module_address && next_head.PreviousModule() == module_address) { + next_head.SetPreviousModule(previous.module_address); + } else if (previous_head.module_address && previous_head.PreviousModule() == module_address) { + previous_head.SetPreviousModule(previous.module_address); + } else { + UNREACHABLE(); + } + } + + // unlink self + SetNextModule(0); + SetPreviousModule(0); +} + +u32 CROHelper::GetFixEnd(u32 fix_level) const { + u32 end = CRO_HEADER_SIZE; + end = std::max(end, GetField(CodeOffset) + GetField(CodeSize)); + + u32 entry_size_i = 2; + int field = ModuleNameOffset; + while (true) { + end = std::max(end, + GetField(static_cast(field)) + + GetField(static_cast(field + 1)) * ENTRY_SIZE[entry_size_i]); + + ++entry_size_i; + field += 2; + + if (field == FIX_BARRIERS[fix_level]) + return end; + } +} + +u32 CROHelper::Fix(u32 fix_level) { + u32 fix_end = GetFixEnd(fix_level); + + if (fix_level != 0) { + SetField(Magic, MAGIC_FIXD); + + for (int field = FIX_BARRIERS[fix_level]; field < Fix0Barrier; field += 2) { + SetField(static_cast(field), fix_end); + SetField(static_cast(field + 1), 0); + } + } + + fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE); + + u32 fixed_size = fix_end - module_address; + SetField(FixedSize, fixed_size); + return fixed_size; +} + +bool CROHelper::IsLoaded() const { + u32 magic = GetField(Magic); + if (magic != MAGIC_CRO0 && magic != MAGIC_FIXD) + return false; + + // TODO(wwylele): verify memory state here after memory aliasing is implemented + + return true; +} + +std::tuple CROHelper::GetExecutablePages() const { + u32 segment_num = GetField(SegmentNum); + for (u32 i = 0; i < segment_num; ++i) { + SegmentEntry entry; + GetEntry(i, entry); + if (entry.type == SegmentType::Code && entry.size != 0) { + VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE); + VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE); + return std::make_tuple(begin, end - begin); + } + } + return std::make_tuple(0, 0); +} + +} // namespace diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h new file mode 100644 index 000000000..34e357afd --- /dev/null +++ b/src/core/hle/service/ldr_ro/cro_helper.h @@ -0,0 +1,691 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "common/swap.h" + +#include "core/memory.h" +#include "core/hle/result.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace LDR_RO + +namespace LDR_RO { + +// GCC versions < 5.0 do not implement std::is_trivially_copyable. +// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable. +#if (__GNUC__ >= 5) || defined(__clang__) + #define ASSERT_CRO_STRUCT(name, size) \ + static_assert(std::is_standard_layout::value, "CRO structure " #name " doesn't use standard layout"); \ + static_assert(std::is_trivially_copyable::value, "CRO structure " #name " isn't trivially copyable"); \ + static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) +#else + #define ASSERT_CRO_STRUCT(name, size) \ + static_assert(std::is_standard_layout::value, "CRO structure " #name " doesn't use standard layout"); \ + static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) +#endif + +static constexpr u32 CRO_HEADER_SIZE = 0x138; +static constexpr u32 CRO_HASH_SIZE = 0x80; + +/// Represents a loaded module (CRO) with interfaces manipulating it. +class CROHelper final { +public: + explicit CROHelper(VAddr cro_address) : module_address(cro_address) { + } + + std::string ModuleName() const { + return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize)); + } + + u32 GetFileSize() const { + return GetField(FileSize); + } + + /** + * Rebases the module according to its address. + * @param crs_address the virtual address of the static module + * @param cro_size the size of the CRO file + * @param data_segment_address buffer address for .data segment + * @param data_segment_size the buffer size for .data segment + * @param bss_segment_address the buffer address for .bss segment + * @param bss_segment_size the buffer size for .bss segment + * @param is_crs true if the module itself is the static module + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode Rebase(VAddr crs_address, u32 cro_size, + VAddr data_segment_addresss, u32 data_segment_size, + VAddr bss_segment_address, u32 bss_segment_size, bool is_crs); + + /** + * Unrebases the module. + * @param is_crs true if the module itself is the static module + */ + void Unrebase(bool is_crs); + + /** + * Verifies module hash by CRR. + * @param cro_size the size of the CRO + * @param crr the virtual address of the CRR + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode VerifyHash(u32 cro_size, VAddr crr) const; + + /** + * Links this module with all registered auto-link module. + * @param crs_address the virtual address of the static module + * @param link_on_load_bug_fix true if links when loading and fixes the bug + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode Link(VAddr crs_address, bool link_on_load_bug_fix); + + /** + * Unlinks this module with other modules. + * @param crs_address the virtual address of the static module + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode Unlink(VAddr crs_address); + + /** + * Clears all relocations to zero. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ClearRelocations(); + + /// Initialize this module as the static module (CRS) + void InitCRS(); + + /** + * Registers this module and adds it to the module list. + * @param crs_address the virtual address of the static module + * @auto_link whether to register as an auto link module + */ + void Register(VAddr crs_address, bool auto_link); + + /** + * Unregisters this module and removes from the module list. + * @param crs_address the virtual address of the static module + */ + void Unregister(VAddr crs_address); + + /** + * Gets the end of reserved data according to the fix level. + * @param fix_level fix level from 0 to 3 + * @returns the end of reserved data. + */ + u32 GetFixEnd(u32 fix_level) const; + + /** + * Zeros offsets to cropped data according to the fix level and marks as fixed. + * @param fix_level fix level from 0 to 3 + * @returns page-aligned size of the module after fixing. + */ + u32 Fix(u32 fix_level); + + bool IsFixed() const { + return GetField(Magic) == MAGIC_FIXD; + } + + u32 GetFixedSize() const { + return GetField(FixedSize); + } + + bool IsLoaded() const; + + /** + * Gets the page address and size of the code segment. + * @returns a tuple of (address, size); (0, 0) if the code segment doesn't exist. + */ + std::tuple GetExecutablePages() const; + +private: + const VAddr module_address; ///< the virtual address of this module + + /** + * Each item in this enum represents a u32 field in the header begin from address+0x80, successively. + * We don't directly use a struct here, to avoid GetPointer, reinterpret_cast, or Read/WriteBlock repeatedly. + */ + enum HeaderField { + Magic = 0, + NameOffset, + NextCRO, + PreviousCRO, + FileSize, + BssSize, + FixedSize, + UnknownZero, + UnkSegmentTag, + OnLoadSegmentTag, + OnExitSegmentTag, + OnUnresolvedSegmentTag, + + CodeOffset, + CodeSize, + DataOffset, + DataSize, + ModuleNameOffset, + ModuleNameSize, + SegmentTableOffset, + SegmentNum, + + ExportNamedSymbolTableOffset, + ExportNamedSymbolNum, + ExportIndexedSymbolTableOffset, + ExportIndexedSymbolNum, + ExportStringsOffset, + ExportStringsSize, + ExportTreeTableOffset, + ExportTreeNum, + + ImportModuleTableOffset, + ImportModuleNum, + ExternalRelocationTableOffset, + ExternalRelocationNum, + ImportNamedSymbolTableOffset, + ImportNamedSymbolNum, + ImportIndexedSymbolTableOffset, + ImportIndexedSymbolNum, + ImportAnonymousSymbolTableOffset, + ImportAnonymousSymbolNum, + ImportStringsOffset, + ImportStringsSize, + + StaticAnonymousSymbolTableOffset, + StaticAnonymousSymbolNum, + InternalRelocationTableOffset, + InternalRelocationNum, + StaticRelocationTableOffset, + StaticRelocationNum, + Fix0Barrier, + + Fix3Barrier = ExportNamedSymbolTableOffset, + Fix2Barrier = ImportModuleTableOffset, + Fix1Barrier = StaticAnonymousSymbolTableOffset, + }; + static_assert(Fix0Barrier == (CRO_HEADER_SIZE - CRO_HASH_SIZE) / 4, "CRO Header fields are wrong!"); + + enum class SegmentType : u32 { + Code = 0, + ROData = 1, + Data = 2, + BSS = 3, + }; + + /** + * Identifies a program location inside of a segment. + * Required to refer to program locations because individual segments may be relocated independently of each other. + */ + union SegmentTag { + u32_le raw; + BitField<0, 4, u32_le> segment_index; + BitField<4, 28, u32_le> offset_into_segment; + + SegmentTag() = default; + explicit SegmentTag(u32 raw_) : raw(raw_) {} + }; + + /// Information of a segment in this module. + struct SegmentEntry { + u32_le offset; + u32_le size; + SegmentType type; + + static constexpr HeaderField TABLE_OFFSET_FIELD = SegmentTableOffset; + }; + ASSERT_CRO_STRUCT(SegmentEntry, 12); + + /// Identifies a named symbol exported from this module. + struct ExportNamedSymbolEntry { + u32_le name_offset; // pointing to a substring in ExportStrings + SegmentTag symbol_position; // to self's segment + + static constexpr HeaderField TABLE_OFFSET_FIELD = ExportNamedSymbolTableOffset; + }; + ASSERT_CRO_STRUCT(ExportNamedSymbolEntry, 8); + + /// Identifies an indexed symbol exported from this module. + struct ExportIndexedSymbolEntry { + SegmentTag symbol_position; // to self's segment + + static constexpr HeaderField TABLE_OFFSET_FIELD = ExportIndexedSymbolTableOffset; + }; + ASSERT_CRO_STRUCT(ExportIndexedSymbolEntry, 4); + + /// A tree node in the symbol lookup tree. + struct ExportTreeEntry { + u16_le test_bit; // bit address into the name to test + union Child { + u16_le raw; + BitField<0, 15, u16_le> next_index; + BitField<15, 1, u16_le> is_end; + } left, right; + u16_le export_table_index; // index of an ExportNamedSymbolEntry + + static constexpr HeaderField TABLE_OFFSET_FIELD = ExportTreeTableOffset; + }; + ASSERT_CRO_STRUCT(ExportTreeEntry, 8); + + /// Identifies a named symbol imported from another module. + struct ImportNamedSymbolEntry { + u32_le name_offset; // pointing to a substring in ImportStrings + u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable + + static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset; + }; + ASSERT_CRO_STRUCT(ImportNamedSymbolEntry, 8); + + /// Identifies an indexed symbol imported from another module. + struct ImportIndexedSymbolEntry { + u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module + u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable + + static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset; + }; + ASSERT_CRO_STRUCT(ImportIndexedSymbolEntry, 8); + + /// Identifies an anonymous symbol imported from another module. + struct ImportAnonymousSymbolEntry { + SegmentTag symbol_position; // in the exporting segment + u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable + + static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset; + }; + ASSERT_CRO_STRUCT(ImportAnonymousSymbolEntry, 8); + + /// Information of a imported module and symbols imported from it. + struct ImportModuleEntry { + u32_le name_offset; // pointing to a substring in ImportStrings + u32_le import_indexed_symbol_table_offset; // pointing to a subtable in ImportIndexedSymbolTable + u32_le import_indexed_symbol_num; + u32_le import_anonymous_symbol_table_offset; // pointing to a subtable in ImportAnonymousSymbolTable + u32_le import_anonymous_symbol_num; + + static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset; + + void GetImportIndexedSymbolEntry(u32 index, ImportIndexedSymbolEntry& entry) { + Memory::ReadBlock(import_indexed_symbol_table_offset + index * sizeof(ImportIndexedSymbolEntry), + &entry, sizeof(ImportIndexedSymbolEntry)); + } + + void GetImportAnonymousSymbolEntry(u32 index, ImportAnonymousSymbolEntry& entry) { + Memory::ReadBlock(import_anonymous_symbol_table_offset + index * sizeof(ImportAnonymousSymbolEntry), + &entry, sizeof(ImportAnonymousSymbolEntry)); + } + }; + ASSERT_CRO_STRUCT(ImportModuleEntry, 20); + + enum class RelocationType : u8 { + Nothing = 0, + AbsoluteAddress = 2, + RelativeAddress = 3, + ThumbBranch = 10, + ArmBranch = 28, + ModifyArmBranch = 29, + AbsoluteAddress2 = 38, + AlignedRelativeAddress = 42, + }; + + struct RelocationEntry { + SegmentTag target_position; // to self's segment as an ExternalRelocationEntry; to static module segment as a StaticRelocationEntry + RelocationType type; + u8 is_batch_end; + u8 is_batch_resolved; // set at a batch beginning if the batch is resolved + INSERT_PADDING_BYTES(1); + u32_le addend; + }; + + /// Identifies a normal cross-module relocation. + struct ExternalRelocationEntry : RelocationEntry { + static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalRelocationTableOffset; + }; + ASSERT_CRO_STRUCT(ExternalRelocationEntry, 12); + + /// Identifies a special static relocation (no game is known using this). + struct StaticRelocationEntry : RelocationEntry { + static constexpr HeaderField TABLE_OFFSET_FIELD = StaticRelocationTableOffset; + }; + ASSERT_CRO_STRUCT(StaticRelocationEntry, 12); + + /// Identifies a in-module relocation. + struct InternalRelocationEntry { + SegmentTag target_position; // to self's segment + RelocationType type; + u8 symbol_segment; + INSERT_PADDING_BYTES(2); + u32_le addend; + + static constexpr HeaderField TABLE_OFFSET_FIELD = InternalRelocationTableOffset; + }; + ASSERT_CRO_STRUCT(InternalRelocationEntry, 12); + + /// Identifies a special static anonymous symbol (no game is known using this). + struct StaticAnonymousSymbolEntry { + SegmentTag symbol_position; // to self's segment + u32_le relocation_batch_offset; // pointing to a relocation batch in StaticRelocationTable + + static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset; + }; + ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8); + + /** + * Entry size of each table, from Code to StaticRelocationTable. + * Byte string contents (such as Code) are treated with entries of size 1. + * This is used for verifying the size of each table and calculating the fix end. + */ + static const std::array ENTRY_SIZE; + + /// The offset field of the table where to crop for each fix level + static const std::array FIX_BARRIERS; + + static constexpr u32 MAGIC_CRO0 = 0x304F5243; + static constexpr u32 MAGIC_FIXD = 0x44584946; + + VAddr Field(HeaderField field) const { + return module_address + CRO_HASH_SIZE + field * 4; + } + + u32 GetField(HeaderField field) const { + return Memory::Read32(Field(field)); + } + + void SetField(HeaderField field, u32 value) { + Memory::Write32(Field(field), value); + } + + /** + * Reads an entry in one of module tables. + * @param index index of the entry + * @param data where to put the read entry + * @note the entry type must have the static member TABLE_OFFSET_FIELD + * indicating which table the entry is in. + */ + template + void GetEntry(std::size_t index, T& data) const { + Memory::ReadBlock(GetField(T::TABLE_OFFSET_FIELD) + index * sizeof(T), &data, sizeof(T)); + } + + /** + * Writes an entry to one of module tables. + * @param index index of the entry + * @param data the entry data to write + * @note the entry type must have the static member TABLE_OFFSET_FIELD + * indicating which table the entry is in. + */ + template + void SetEntry(std::size_t index, const T& data) { + Memory::WriteBlock(GetField(T::TABLE_OFFSET_FIELD) + index * sizeof(T), &data, sizeof(T)); + } + + /** + * Converts a segment tag to virtual address in this module. + * @param segment_tag the segment tag to convert + * @returns VAddr the virtual address the segment tag points to; 0 if invalid. + */ + VAddr SegmentTagToAddress(SegmentTag segment_tag) const; + + VAddr NextModule() const { + return GetField(NextCRO); + } + + VAddr PreviousModule() const { + return GetField(PreviousCRO); + } + + void SetNextModule(VAddr next) { + SetField(NextCRO, next); + } + + void SetPreviousModule(VAddr previous) { + SetField(PreviousCRO, previous); + } + + /** + * A helper function iterating over all registered auto-link modules, including the static module. + * @param crs_address the virtual address of the static module + * @param func a function object to operate on a module. It accepts one parameter + * CROHelper and returns ResultVal. It should return true to continue the iteration, + * false to stop the iteration, or an error code (which will also stop the iteration). + * @returns ResultCode indicating the result of the operation, RESULT_SUCCESS if all iteration success, + * otherwise error code of the last iteration. + */ + template + static ResultCode ForEachAutoLinkCRO(VAddr crs_address, FunctionObject func) { + VAddr current = crs_address; + while (current != 0) { + CROHelper cro(current); + CASCADE_RESULT(bool next, func(cro)); + if (!next) + break; + current = cro.NextModule(); + } + return RESULT_SUCCESS; + } + + /** + * Applies a relocation + * @param target_address where to apply the relocation + * @param relocation_type the type of the relocation + * @param addend address addend applied to the relocated symbol + * @param symbol_address the symbol address to be relocated with + * @param target_future_address the future address of the target. + * Usually equals to target_address, but will be different for a target in .data segment + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyRelocation(VAddr target_address, RelocationType relocation_type, + u32 addend, u32 symbol_address, u32 target_future_address); + + /** + * Clears a relocation to zero + * @param target_address where to apply the relocation + * @param relocation_type the type of the relocation + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ClearRelocation(VAddr target_address, RelocationType relocation_type); + + /** + * Applies or resets a batch of relocations + * @param batch the virtual address of the first relocation in the batch + * @param symbol_address the symbol address to be relocated with + * @param reset false to set the batch to resolved state, true to reset the batch to unresolved state + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset = false); + + /** + * Finds an exported named symbol in this module. + * @param name the name of the symbol to find + * @return VAddr the virtual address of the symbol; 0 if not found. + */ + VAddr FindExportNamedSymbol(const std::string& name) const; + + /** + * Rebases offsets in module header according to module address. + * @param cro_size the size of the CRO file + * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code. + */ + ResultCode RebaseHeader(u32 cro_size); + + /** + * Rebases offsets in segment table according to module address. + * @param cro_size the size of the CRO file + * @param data_segment_address the buffer address for .data segment + * @param data_segment_size the buffer size for .data segment + * @param bss_segment_address the buffer address for .bss segment + * @param bss_segment_size the buffer size for .bss segment + * @returns ResultVal with the virtual address of .data segment in CRO. + */ + ResultVal RebaseSegmentTable(u32 cro_size, + VAddr data_segment_address, u32 data_segment_size, + VAddr bss_segment_address, u32 bss_segment_size); + + /** + * Rebases offsets in exported named symbol table according to module address. + * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code. + */ + ResultCode RebaseExportNamedSymbolTable(); + + /** + * Verifies indices in export tree table. + * @returns ResultCode RESULT_SUCCESS if all indices are verified as valid, otherwise error code. + */ + ResultCode VerifyExportTreeTable() const; + + /** + * Rebases offsets in exported module table according to module address. + * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code. + */ + ResultCode RebaseImportModuleTable(); + + /** + * Rebases offsets in imported named symbol table according to module address. + * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code. + */ + ResultCode RebaseImportNamedSymbolTable(); + + /** + * Rebases offsets in imported indexed symbol table according to module address. + * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code. + */ + ResultCode RebaseImportIndexedSymbolTable(); + + /** + * Rebases offsets in imported anonymous symbol table according to module address. + * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code. + */ + ResultCode RebaseImportAnonymousSymbolTable(); + + /** + * Gets the address of OnUnresolved function in this module. + * Used as the applied symbol for reset relocation. + * @returns the virtual address of OnUnresolved. 0 if not provided. + */ + VAddr GetOnUnresolvedAddress(); + + /** + * Resets all external relocations to unresolved state. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ResetExternalRelocations(); + + /** + * Clears all external relocations to zero. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ClearExternalRelocations(); + + /** + * Applies all static anonymous symbol to the static module. + * @param crs_address the virtual address of the static module + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address); + + /** + * Applies all internal relocations to the module itself. + * @param old_data_segment_address the virtual address of data segment in CRO buffer + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyInternalRelocations(u32 old_data_segment_address); + + /** + * Clears all internal relocations to zero. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ClearInternalRelocations(); + + /// Unrebases offsets in imported anonymous symbol table + void UnrebaseImportAnonymousSymbolTable(); + + /// Unrebases offsets in imported indexed symbol table + void UnrebaseImportIndexedSymbolTable(); + + /// Unrebases offsets in imported named symbol table + void UnrebaseImportNamedSymbolTable(); + + /// Unrebases offsets in imported module table + void UnrebaseImportModuleTable(); + + /// Unrebases offsets in exported named symbol table + void UnrebaseExportNamedSymbolTable(); + + /// Unrebases offsets in segment table + void UnrebaseSegmentTable(); + + /// Unrebases offsets in module header + void UnrebaseHeader(); + + /** + * Looks up all imported named symbols of this module in all registered auto-link modules, and resolves them if found. + * @param crs_address the virtual address of the static module + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyImportNamedSymbol(VAddr crs_address); + + /** + * Resets all imported named symbols of this module to unresolved state. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ResetImportNamedSymbol(); + + /** + * Resets all imported indexed symbols of this module to unresolved state. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ResetImportIndexedSymbol(); + + /** + * Resets all imported anonymous symbols of this module to unresolved state. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ResetImportAnonymousSymbol(); + + /** + * Finds registered auto-link modules that this module imports, and resolves indexed and anonymous symbols exported by them. + * @param crs_address the virtual address of the static module + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyModuleImport(VAddr crs_address); + + /** + * Resolves target module's imported named symbols that exported by this module. + * @param target the module to resolve. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyExportNamedSymbol(CROHelper target); + + /** + * Resets target's named symbols imported from this module to unresolved state. + * @param target the module to reset. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ResetExportNamedSymbol(CROHelper target); + + /** + * Resolves imported indexed and anonymous symbols in the target module which imports this module. + * @param target the module to resolve. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyModuleExport(CROHelper target); + + /** + * Resets target's indexed and anonymous symbol imported from this module to unresolved state. + * @param target the module to reset. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ResetModuleExport(CROHelper target); + + /** + * Resolves the exit function in this module + * @param crs_address the virtual address of the static module. + * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. + */ + ResultCode ApplyExitRelocations(VAddr crs_address); +}; + +} // namespace diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp new file mode 100644 index 000000000..8ba73ea8d --- /dev/null +++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp @@ -0,0 +1,748 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/alignment.h" +#include "common/common_types.h" +#include "common/logging/log.h" + +#include "core/arm/arm_interface.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/vm_manager.h" +#include "core/hle/service/ldr_ro/cro_helper.h" +#include "core/hle/service/ldr_ro/ldr_ro.h" +#include "core/hle/service/ldr_ro/memory_synchronizer.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace LDR_RO + +namespace LDR_RO { + +static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9 + ResultCode(ErrorDescription::AlreadyInitialized, ErrorModule::RO, ErrorSummary::Internal, ErrorLevel::Permanent); +static const ResultCode ERROR_NOT_INITIALIZED = // 0xD9612FF8 + ResultCode(ErrorDescription::NotInitialized, ErrorModule::RO, ErrorSummary::Internal, ErrorLevel::Permanent); +static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F + ResultCode(static_cast(31), ErrorModule::RO, ErrorSummary::InvalidArgument, ErrorLevel::Usage); +static const ResultCode ERROR_MISALIGNED_ADDRESS = // 0xD9012FF1 + ResultCode(ErrorDescription::MisalignedAddress, ErrorModule::RO, ErrorSummary::WrongArgument, ErrorLevel::Permanent); +static const ResultCode ERROR_MISALIGNED_SIZE = // 0xD9012FF2 + ResultCode(ErrorDescription::MisalignedSize, ErrorModule::RO, ErrorSummary::WrongArgument, ErrorLevel::Permanent); +static const ResultCode ERROR_ILLEGAL_ADDRESS = // 0xE1612C0F + ResultCode(static_cast(15), ErrorModule::RO, ErrorSummary::Internal, ErrorLevel::Usage); +static const ResultCode ERROR_INVALID_MEMORY_STATE = // 0xD8A12C08 + ResultCode(static_cast(8), ErrorModule::RO, ErrorSummary::InvalidState, ErrorLevel::Permanent); +static const ResultCode ERROR_NOT_LOADED = // 0xD8A12C0D + ResultCode(static_cast(13), ErrorModule::RO, ErrorSummary::InvalidState, ErrorLevel::Permanent); +static const ResultCode ERROR_INVALID_DESCRIPTOR = // 0xD9001830 + ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent); + +static MemorySynchronizer memory_synchronizer; + +// TODO(wwylele): this should be in the per-client storage when we implement multi-process +static VAddr loaded_crs; ///< the virtual address of the static module + +static bool VerifyBufferState(VAddr buffer_ptr, u32 size) { + auto vma = Kernel::g_current_process->vm_manager.FindVMA(buffer_ptr); + return vma != Kernel::g_current_process->vm_manager.vma_map.end() + && vma->second.base + vma->second.size >= buffer_ptr + size + && vma->second.permissions == Kernel::VMAPermission::ReadWrite + && vma->second.meminfo_state == Kernel::MemoryState::Private; +} + +/** + * LDR_RO::Initialize service function + * Inputs: + * 0 : 0x000100C2 + * 1 : CRS buffer pointer + * 2 : CRS Size + * 3 : Process memory address where the CRS will be mapped + * 4 : handle translation descriptor (zero) + * 5 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void Initialize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + VAddr crs_buffer_ptr = cmd_buff[1]; + u32 crs_size = cmd_buff[2]; + VAddr crs_address = cmd_buff[3]; + u32 descriptor = cmd_buff[4]; + u32 process = cmd_buff[5]; + + LOG_DEBUG(Service_LDR, "called, crs_buffer_ptr=0x%08X, crs_address=0x%08X, crs_size=0x%X, descriptor=0x%08X, process=0x%08X", + crs_buffer_ptr, crs_address, crs_size, descriptor, process); + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + cmd_buff[0] = IPC::MakeHeader(1, 1, 0); + + if (loaded_crs != 0) { + LOG_ERROR(Service_LDR, "Already initialized"); + cmd_buff[1] = ERROR_ALREADY_INITIALIZED.raw; + return; + } + + if (crs_size < CRO_HEADER_SIZE) { + LOG_ERROR(Service_LDR, "CRS is too small"); + cmd_buff[1] = ERROR_BUFFER_TOO_SMALL.raw; + return; + } + + if (crs_buffer_ptr & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRS original address is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_ADDRESS.raw; + return; + } + + if (crs_address & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRS mapping address is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_ADDRESS.raw; + return; + } + + if (crs_size & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRS size is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_SIZE.raw; + return; + } + + if (!VerifyBufferState(crs_buffer_ptr, crs_size)) { + LOG_ERROR(Service_LDR, "CRS original buffer is in invalid state"); + cmd_buff[1] = ERROR_INVALID_MEMORY_STATE.raw; + return; + } + + if (crs_address < Memory::PROCESS_IMAGE_VADDR || crs_address + crs_size > Memory::PROCESS_IMAGE_VADDR_END) { + LOG_ERROR(Service_LDR, "CRS mapping address is not in the process image region"); + cmd_buff[1] = ERROR_ILLEGAL_ADDRESS.raw; + return; + } + + ResultCode result = RESULT_SUCCESS; + + if (crs_buffer_ptr != crs_address) { + // TODO(wwylele): should be memory aliasing + std::shared_ptr> crs_mem = std::make_shared>(crs_size); + Memory::ReadBlock(crs_buffer_ptr, crs_mem->data(), crs_size); + result = Kernel::g_current_process->vm_manager.MapMemoryBlock(crs_address, crs_mem, 0, crs_size, Kernel::MemoryState::Code).Code(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw); + cmd_buff[1] = result.raw; + return; + } + + result = Kernel::g_current_process->vm_manager.ReprotectRange(crs_address, crs_size, Kernel::VMAPermission::Read); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); + cmd_buff[1] = result.raw; + return; + } + + memory_synchronizer.AddMemoryBlock(crs_address, crs_buffer_ptr, crs_size); + } else { + // Do nothing if buffer_ptr == address + // TODO(wwylele): verify this behaviour. This is only seen in the web browser app, + // and the actual behaviour is unclear. "Do nothing" is probably an incorrect implement. + // There is also a chance that another issue causes the app passing wrong arguments. + LOG_WARNING(Service_LDR, "crs_buffer_ptr == crs_address (0x%08X)", crs_address); + } + + CROHelper crs(crs_address); + crs.InitCRS(); + + result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing CRS 0x%08X", result.raw); + cmd_buff[1] = result.raw; + return; + } + + memory_synchronizer.SynchronizeOriginalMemory(); + + loaded_crs = crs_address; + + cmd_buff[1] = RESULT_SUCCESS.raw; +} + +/** + * LDR_RO::LoadCRR service function + * Inputs: + * 0 : 0x00020082 + * 1 : CRR buffer pointer + * 2 : CRR Size + * 3 : handle translation descriptor (zero) + * 4 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void LoadCRR(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 crr_buffer_ptr = cmd_buff[1]; + u32 crr_size = cmd_buff[2]; + u32 descriptor = cmd_buff[3]; + u32 process = cmd_buff[4]; + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + cmd_buff[0] = IPC::MakeHeader(2, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_LDR, "(STUBBED) called, crr_buffer_ptr=0x%08X, crr_size=0x%08X, descriptor=0x%08X, process=0x%08X", + crr_buffer_ptr, crr_size, descriptor, process); +} + +/** + * LDR_RO::UnloadCRR service function + * Inputs: + * 0 : 0x00030042 + * 1 : CRR buffer pointer + * 2 : handle translation descriptor (zero) + * 3 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void UnloadCRR(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 crr_buffer_ptr = cmd_buff[1]; + u32 descriptor = cmd_buff[2]; + u32 process = cmd_buff[3]; + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + cmd_buff[0] = IPC::MakeHeader(3, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_LDR, "(STUBBED) called, crr_buffer_ptr=0x%08X, descriptor=0x%08X, process=0x%08X", + crr_buffer_ptr, descriptor, process); +} + +/** + * LDR_RO::LoadCRO service function + * Inputs: + * 0 : 0x000402C2 (old) / 0x000902C2 (new) + * 1 : CRO buffer pointer + * 2 : memory address where the CRO will be mapped + * 3 : CRO Size + * 4 : .data segment buffer pointer + * 5 : must be zero + * 6 : .data segment buffer size + * 7 : .bss segment buffer pointer + * 8 : .bss segment buffer size + * 9 : (bool) register CRO as auto-link module + * 10 : fix level + * 11 : CRR address (zero if use loaded CRR) + * 12 : handle translation descriptor (zero) + * 13 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : CRO fixed size + * Note: + * This service function has two versions. The function defined here is a + * unified one of two, with an additional parameter link_on_load_bug_fix. + * There is a dispatcher template below. + */ +static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + VAddr cro_buffer_ptr = cmd_buff[1]; + VAddr cro_address = cmd_buff[2]; + u32 cro_size = cmd_buff[3]; + VAddr data_segment_address = cmd_buff[4]; + u32 zero = cmd_buff[5]; + u32 data_segment_size = cmd_buff[6]; + u32 bss_segment_address = cmd_buff[7]; + u32 bss_segment_size = cmd_buff[8]; + bool auto_link = (cmd_buff[9] & 0xFF) != 0; + u32 fix_level = cmd_buff[10]; + VAddr crr_address = cmd_buff[11]; + u32 descriptor = cmd_buff[12]; + u32 process = cmd_buff[13]; + + LOG_DEBUG(Service_LDR, "called (%s), cro_buffer_ptr=0x%08X, cro_address=0x%08X, cro_size=0x%X, " + "data_segment_address=0x%08X, zero=%d, data_segment_size=0x%X, bss_segment_address=0x%08X, bss_segment_size=0x%X, " + "auto_link=%s, fix_level=%d, crr_address=0x%08X, descriptor=0x%08X, process=0x%08X", + link_on_load_bug_fix ? "new" : "old", cro_buffer_ptr, cro_address, cro_size, + data_segment_address, zero, data_segment_size, bss_segment_address, bss_segment_size, + auto_link ? "true" : "false", fix_level, crr_address, descriptor, process + ); + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + cmd_buff[0] = IPC::MakeHeader(link_on_load_bug_fix ? 9 : 4, 2, 0); + + if (loaded_crs == 0) { + LOG_ERROR(Service_LDR, "Not initialized"); + cmd_buff[1] = ERROR_NOT_INITIALIZED.raw; + return; + } + + if (cro_size < CRO_HEADER_SIZE) { + LOG_ERROR(Service_LDR, "CRO too small"); + cmd_buff[1] = ERROR_BUFFER_TOO_SMALL.raw; + return; + } + + if (cro_buffer_ptr & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRO original address is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_ADDRESS.raw; + return; + } + + if (cro_address & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRO mapping address is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_ADDRESS.raw; + return; + } + + if (cro_size & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRO size is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_SIZE.raw; + return; + } + + if (!VerifyBufferState(cro_buffer_ptr, cro_size)) { + LOG_ERROR(Service_LDR, "CRO original buffer is in invalid state"); + cmd_buff[1] = ERROR_INVALID_MEMORY_STATE.raw; + return; + } + + if (cro_address < Memory::PROCESS_IMAGE_VADDR + || cro_address + cro_size > Memory::PROCESS_IMAGE_VADDR_END) { + LOG_ERROR(Service_LDR, "CRO mapping address is not in the process image region"); + cmd_buff[1] = ERROR_ILLEGAL_ADDRESS.raw; + return; + } + + if (zero) { + LOG_ERROR(Service_LDR, "Zero is not zero %d", zero); + cmd_buff[1] = ResultCode(static_cast(29), ErrorModule::RO, ErrorSummary::Internal, ErrorLevel::Usage).raw; + return; + } + + ResultCode result = RESULT_SUCCESS; + + if (cro_buffer_ptr != cro_address) { + // TODO(wwylele): should be memory aliasing + std::shared_ptr> cro_mem = std::make_shared>(cro_size); + Memory::ReadBlock(cro_buffer_ptr, cro_mem->data(), cro_size); + result = Kernel::g_current_process->vm_manager.MapMemoryBlock(cro_address, cro_mem, 0, cro_size, Kernel::MemoryState::Code).Code(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw); + cmd_buff[1] = result.raw; + return; + } + + result = Kernel::g_current_process->vm_manager.ReprotectRange(cro_address, cro_size, Kernel::VMAPermission::Read); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); + Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); + cmd_buff[1] = result.raw; + return; + } + + memory_synchronizer.AddMemoryBlock(cro_address, cro_buffer_ptr, cro_size); + } else { + // Do nothing if buffer_ptr == address + // TODO(wwylele): verify this behaviour. + // This is derived from the case of LoadCRS with buffer_ptr==address, + // and is never seen in any game. "Do nothing" is probably an incorrect implement. + // There is also a chance that this case is just prohibited. + LOG_WARNING(Service_LDR, "cro_buffer_ptr == cro_address (0x%08X)", cro_address); + } + + CROHelper cro(cro_address); + + result = cro.VerifyHash(cro_size, crr_address); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error verifying CRO in CRR %08X", result.raw); + Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); + cmd_buff[1] = result.raw; + return; + } + + result = cro.Rebase(loaded_crs, cro_size, data_segment_address, data_segment_size, bss_segment_address, bss_segment_size, false); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error rebasing CRO %08X", result.raw); + Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); + cmd_buff[1] = result.raw; + return; + } + + result = cro.Link(loaded_crs, link_on_load_bug_fix); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw); + Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); + cmd_buff[1] = result.raw; + return; + } + + cro.Register(loaded_crs, auto_link); + + u32 fix_size = cro.Fix(fix_level); + + memory_synchronizer.SynchronizeOriginalMemory(); + + // TODO(wwylele): verify the behaviour when buffer_ptr == address + if (cro_buffer_ptr != cro_address) { + if (fix_size != cro_size) { + result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address + fix_size, cro_size - fix_size); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error unmapping memory block %08X", result.raw); + Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); + cmd_buff[1] = result.raw; + return; + } + } + + // Changes the block size + memory_synchronizer.ResizeMemoryBlock(cro_address, cro_buffer_ptr, fix_size); + } + + VAddr exe_begin; + u32 exe_size; + std::tie(exe_begin, exe_size) = cro.GetExecutablePages(); + if (exe_begin) { + result = Kernel::g_current_process->vm_manager.ReprotectRange(exe_begin, exe_size, Kernel::VMAPermission::ReadExecute); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); + Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fix_size); + cmd_buff[1] = result.raw; + return; + } + } + + Core::g_app_core->ClearInstructionCache(); + + LOG_INFO(Service_LDR, "CRO \"%s\" loaded at 0x%08X, fixed_end=0x%08X", + cro.ModuleName().data(), cro_address, cro_address+fix_size); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = fix_size; +} + +template +static void LoadCRO(Service::Interface* self) { + LoadCRO(self, link_on_load_bug_fix); +} + +/** + * LDR_RO::UnloadCRO service function + * Inputs: + * 0 : 0x000500C2 + * 1 : mapped CRO pointer + * 2 : zero? (RO service doesn't care) + * 3 : original CRO pointer + * 4 : handle translation descriptor (zero) + * 5 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void UnloadCRO(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + VAddr cro_address = cmd_buff[1]; + u32 zero = cmd_buff[2]; + VAddr cro_buffer_ptr = cmd_buff[3]; + u32 descriptor = cmd_buff[4]; + u32 process = cmd_buff[5]; + + LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, zero=%d, cro_buffer_ptr=0x%08X, descriptor=0x%08X, process=0x%08X", + cro_address, zero, cro_buffer_ptr, descriptor, process); + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + CROHelper cro(cro_address); + + cmd_buff[0] = IPC::MakeHeader(5, 1, 0); + + if (loaded_crs == 0) { + LOG_ERROR(Service_LDR, "Not initialized"); + cmd_buff[1] = ERROR_NOT_INITIALIZED.raw; + return; + } + + if (cro_address & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRO address is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_ADDRESS.raw; + return; + } + + if (!cro.IsLoaded()) { + LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); + cmd_buff[1] = ERROR_NOT_LOADED.raw; + return; + } + + LOG_INFO(Service_LDR, "Unloading CRO \"%s\"", cro.ModuleName().data()); + + u32 fixed_size = cro.GetFixedSize(); + + cro.Unregister(loaded_crs); + + ResultCode result = cro.Unlink(loaded_crs); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw); + cmd_buff[1] = result.raw; + return; + } + + // If the module is not fixed, clears all external/internal relocations + // to restore the state before loading, so that it can be loaded again(?) + if (!cro.IsFixed()) { + result = cro.ClearRelocations(); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error clearing relocations %08X", result.raw); + cmd_buff[1] = result.raw; + return; + } + } + + cro.Unrebase(false); + + memory_synchronizer.SynchronizeOriginalMemory(); + + // TODO(wwylele): verify the behaviour when buffer_ptr == address + if (cro_address != cro_buffer_ptr) { + result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fixed_size); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error unmapping CRO %08X", result.raw); + } + memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr); + } + + Core::g_app_core->ClearInstructionCache(); + + cmd_buff[1] = result.raw; +} + +/** + * LDR_RO::LinkCRO service function + * Inputs: + * 0 : 0x00060042 + * 1 : mapped CRO pointer + * 2 : handle translation descriptor (zero) + * 3 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void LinkCRO(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + VAddr cro_address = cmd_buff[1]; + u32 descriptor = cmd_buff[2]; + u32 process = cmd_buff[3]; + + LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, descriptor=0x%08X, process=0x%08X", + cro_address, descriptor, process); + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + CROHelper cro(cro_address); + + cmd_buff[0] = IPC::MakeHeader(6, 1, 0); + + if (loaded_crs == 0) { + LOG_ERROR(Service_LDR, "Not initialized"); + cmd_buff[1] = ERROR_NOT_INITIALIZED.raw; + return; + } + + if (cro_address & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRO address is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_ADDRESS.raw; + return; + } + + if (!cro.IsLoaded()) { + LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); + cmd_buff[1] = ERROR_NOT_LOADED.raw; + return; + } + + LOG_INFO(Service_LDR, "Linking CRO \"%s\"", cro.ModuleName().data()); + + ResultCode result = cro.Link(loaded_crs, false); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw); + } + + memory_synchronizer.SynchronizeOriginalMemory(); + Core::g_app_core->ClearInstructionCache(); + + cmd_buff[1] = result.raw; +} + +/** + * LDR_RO::UnlinkCRO service function + * Inputs: + * 0 : 0x00070042 + * 1 : mapped CRO pointer + * 2 : handle translation descriptor (zero) + * 3 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void UnlinkCRO(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + VAddr cro_address = cmd_buff[1]; + u32 descriptor = cmd_buff[2]; + u32 process = cmd_buff[3]; + + LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, descriptor=0x%08X, process=0x%08X", + cro_address, descriptor, process); + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + CROHelper cro(cro_address); + + cmd_buff[0] = IPC::MakeHeader(7, 1, 0); + + if (loaded_crs == 0) { + LOG_ERROR(Service_LDR, "Not initialized"); + cmd_buff[1] = ERROR_NOT_INITIALIZED.raw; + return; + } + + if (cro_address & Memory::PAGE_MASK) { + LOG_ERROR(Service_LDR, "CRO address is not aligned"); + cmd_buff[1] = ERROR_MISALIGNED_ADDRESS.raw; + return; + } + + if (!cro.IsLoaded()) { + LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); + cmd_buff[1] = ERROR_NOT_LOADED.raw; + return; + } + + LOG_INFO(Service_LDR, "Unlinking CRO \"%s\"", cro.ModuleName().data()); + + ResultCode result = cro.Unlink(loaded_crs); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw); + } + + memory_synchronizer.SynchronizeOriginalMemory(); + Core::g_app_core->ClearInstructionCache(); + + cmd_buff[1] = result.raw; +} + +/** + * LDR_RO::Shutdown service function + * Inputs: + * 0 : 0x00080042 + * 1 : original CRS buffer pointer + * 2 : handle translation descriptor (zero) + * 3 : KProcess handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void Shutdown(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + VAddr crs_buffer_ptr = cmd_buff[1]; + u32 descriptor = cmd_buff[2]; + u32 process = cmd_buff[3]; + + LOG_DEBUG(Service_LDR, "called, crs_buffer_ptr=0x%08X, descriptor=0x%08X, process=0x%08X", + crs_buffer_ptr, descriptor, process); + + if (descriptor != 0) { + LOG_ERROR(Service_LDR, "IPC handle descriptor failed validation (0x%X)", descriptor); + cmd_buff[0] = IPC::MakeHeader(0, 1, 0); + cmd_buff[1] = ERROR_INVALID_DESCRIPTOR.raw; + return; + } + + if (loaded_crs == 0) { + LOG_ERROR(Service_LDR, "Not initialized"); + cmd_buff[1] = ERROR_NOT_INITIALIZED.raw; + return; + } + + cmd_buff[0] = IPC::MakeHeader(8, 1, 0); + + CROHelper crs(loaded_crs); + crs.Unrebase(true); + + memory_synchronizer.SynchronizeOriginalMemory(); + + ResultCode result = RESULT_SUCCESS; + + // TODO(wwylele): verify the behaviour when buffer_ptr == address + if (loaded_crs != crs_buffer_ptr) { + result = Kernel::g_current_process->vm_manager.UnmapRange(loaded_crs, crs.GetFileSize()); + if (result.IsError()) { + LOG_ERROR(Service_LDR, "Error unmapping CRS %08X", result.raw); + } + memory_synchronizer.RemoveMemoryBlock(loaded_crs, crs_buffer_ptr); + } + + loaded_crs = 0; + cmd_buff[1] = result.raw; +} + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C2, Initialize, "Initialize"}, + {0x00020082, LoadCRR, "LoadCRR"}, + {0x00030042, UnloadCRR, "UnloadCRR"}, + {0x000402C2, LoadCRO, "LoadCRO"}, + {0x000500C2, UnloadCRO, "UnloadCRO"}, + {0x00060042, LinkCRO, "LinkCRO"}, + {0x00070042, UnlinkCRO, "UnlinkCRO"}, + {0x00080042, Shutdown, "Shutdown"}, + {0x000902C2, LoadCRO, "LoadCRO_New"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable); + + loaded_crs = 0; + memory_synchronizer.Clear(); +} + +} // namespace diff --git a/src/core/hle/service/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h similarity index 100% rename from src/core/hle/service/ldr_ro.h rename to src/core/hle/service/ldr_ro/ldr_ro.h diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp new file mode 100644 index 000000000..4402876e6 --- /dev/null +++ b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp @@ -0,0 +1,46 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/assert.h" + +#include "core/hle/service/ldr_ro/memory_synchronizer.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace LDR_RO + +namespace LDR_RO { + +auto MemorySynchronizer::FindMemoryBlock(VAddr mapping, VAddr original) { + auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(), [=](MemoryBlock& b){ + return b.original == original; + }); + ASSERT(block->mapping == mapping); + return block; +} + +void MemorySynchronizer::Clear() { + memory_blocks.clear(); +} + +void MemorySynchronizer::AddMemoryBlock(VAddr mapping, VAddr original, u32 size) { + memory_blocks.push_back(MemoryBlock{mapping, original, size}); +} + +void MemorySynchronizer::ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size) { + FindMemoryBlock(mapping, original)->size = size; +} + +void MemorySynchronizer::RemoveMemoryBlock(VAddr mapping, VAddr original) { + memory_blocks.erase(FindMemoryBlock(mapping, original)); +} + +void MemorySynchronizer::SynchronizeOriginalMemory() { + for (auto& block : memory_blocks) { + Memory::CopyBlock(block.original, block.mapping, block.size); + } +} + +} // namespace diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.h b/src/core/hle/service/ldr_ro/memory_synchronizer.h new file mode 100644 index 000000000..92f267912 --- /dev/null +++ b/src/core/hle/service/ldr_ro/memory_synchronizer.h @@ -0,0 +1,44 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "core/memory.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace LDR_RO + +namespace LDR_RO { + +/** + * This is a work-around before we implement memory aliasing. + * CRS and CRO are mapped (aliased) to another memory when loading. Games can read + * from both the original buffer and the mapping memory. So we use this to synchronize + * all original buffers with mapping memory after modifying the content. + */ +class MemorySynchronizer { +public: + void Clear(); + + void AddMemoryBlock(VAddr mapping, VAddr original, u32 size); + void ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size); + void RemoveMemoryBlock(VAddr mapping, VAddr original); + + void SynchronizeOriginalMemory(); + +private: + struct MemoryBlock { + VAddr mapping; + VAddr original; + u32 size; + }; + + std::vector memory_blocks; + + auto FindMemoryBlock(VAddr mapping, VAddr original); +}; + +} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 395880843..5b8440b77 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -15,7 +15,6 @@ #include "core/hle/service/gsp_gpu.h" #include "core/hle/service/gsp_lcd.h" #include "core/hle/service/http_c.h" -#include "core/hle/service/ldr_ro.h" #include "core/hle/service/mic_u.h" #include "core/hle/service/ns_s.h" #include "core/hle/service/nwm_uds.h" @@ -36,6 +35,7 @@ #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/ir/ir.h" +#include "core/hle/service/ldr_ro/ldr_ro.h" #include "core/hle/service/ndm/ndm.h" #include "core/hle/service/news/news.h" #include "core/hle/service/nim/nim.h" From ac6853c58567f29e38ddb775b90fdddede30cf44 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Mon, 29 Aug 2016 15:19:50 +0200 Subject: [PATCH 63/77] AppVeyor: Cache chocolatey packages --- appveyor.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index e82bdf0cf..28c902bee 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,6 +5,10 @@ environment: BUILD_PASSWORD: secure: EXGNlWKJsCtbeImEJ5EP9qrxZ+EqUFfNy+CP61nDOMA= +cache: + - C:\ProgramData\chocolatey\bin -> appveyor.yml + - C:\ProgramData\chocolatey\lib -> appveyor.yml + os: Visual Studio 2015 platform: From 2267f98941ca03e11fbc0ff71ee4b682f8e41933 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 24 Aug 2016 22:15:38 -0400 Subject: [PATCH 64/77] qt: Add a configuration tab for Graphics and move relevant fields. --- src/citra_qt/CMakeLists.txt | 3 + src/citra_qt/configure.ui | 27 ++++++--- src/citra_qt/configure_dialog.cpp | 1 + src/citra_qt/configure_general.cpp | 6 -- src/citra_qt/configure_general.ui | 34 ------------ src/citra_qt/configure_graphics.cpp | 32 +++++++++++ src/citra_qt/configure_graphics.h | 29 ++++++++++ src/citra_qt/configure_graphics.ui | 85 +++++++++++++++++++++++++++++ 8 files changed, 169 insertions(+), 48 deletions(-) create mode 100644 src/citra_qt/configure_graphics.cpp create mode 100644 src/citra_qt/configure_graphics.h create mode 100644 src/citra_qt/configure_graphics.ui diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 4402ad995..e97d33da4 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRCS configure_debug.cpp configure_dialog.cpp configure_general.cpp + configure_graphics.cpp configure_system.cpp configure_input.cpp game_list.cpp @@ -54,6 +55,7 @@ set(HEADERS configure_debug.h configure_dialog.h configure_general.h + configure_graphics.h configure_system.h configure_input.h game_list.h @@ -73,6 +75,7 @@ set(UIS configure_audio.ui configure_debug.ui configure_general.ui + configure_graphics.ui configure_system.ui configure_input.ui hotkeys.ui diff --git a/src/citra_qt/configure.ui b/src/citra_qt/configure.ui index 15fe17323..28b4a3b90 100644 --- a/src/citra_qt/configure.ui +++ b/src/citra_qt/configure.ui @@ -34,11 +34,16 @@ Input
- + - Audio + Graphics + + + Audio + + Debug @@ -80,12 +85,18 @@
configure_debug.h
1 - - ConfigureInput - QWidget -
configure_input.h
- 1 -
+ + ConfigureInput + QWidget +
configure_input.h
+ 1 +
+ + ConfigureGraphics + QWidget +
configure_graphics.h
+ 1 +
diff --git a/src/citra_qt/configure_dialog.cpp b/src/citra_qt/configure_dialog.cpp index 459fac4bb..7da8ad067 100644 --- a/src/citra_qt/configure_dialog.cpp +++ b/src/citra_qt/configure_dialog.cpp @@ -31,6 +31,7 @@ void ConfigureDialog::applyConfiguration() { ui->generalTab->applyConfiguration(); ui->systemTab->applyConfiguration(); ui->inputTab->applyConfiguration(); + ui->graphicsTab->applyConfiguration(); ui->audioTab->applyConfiguration(); ui->debugTab->applyConfiguration(); } diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp index 62648e665..3e7a91885 100644 --- a/src/citra_qt/configure_general.cpp +++ b/src/citra_qt/configure_general.cpp @@ -23,17 +23,11 @@ void ConfigureGeneral::setConfiguration() { ui->toogle_deepscan->setChecked(UISettings::values.gamedir_deepscan); ui->toogle_check_exit->setChecked(UISettings::values.confirm_before_closing); ui->region_combobox->setCurrentIndex(Settings::values.region_value); - ui->toogle_hw_renderer->setChecked(Settings::values.use_hw_renderer); - ui->toogle_shader_jit->setChecked(Settings::values.use_shader_jit); - ui->toogle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution); } void ConfigureGeneral::applyConfiguration() { UISettings::values.gamedir_deepscan = ui->toogle_deepscan->isChecked(); UISettings::values.confirm_before_closing = ui->toogle_check_exit->isChecked(); Settings::values.region_value = ui->region_combobox->currentIndex(); - Settings::values.use_hw_renderer = ui->toogle_hw_renderer->isChecked(); - Settings::values.use_shader_jit = ui->toogle_shader_jit->isChecked(); - Settings::values.use_scaled_resolution = ui->toogle_scaled_resolution->isChecked(); Settings::Apply(); } diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configure_general.ui index 5eb309793..f993f7525 100644 --- a/src/citra_qt/configure_general.ui +++ b/src/citra_qt/configure_general.ui @@ -106,40 +106,6 @@
- - - - Performance - - - - - - - - Enable hardware renderer - - - - - - - Enable shader JIT - - - - - - - Enable scaled resolution - - - - - - - - diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configure_graphics.cpp new file mode 100644 index 000000000..85a120686 --- /dev/null +++ b/src/citra_qt/configure_graphics.cpp @@ -0,0 +1,32 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "citra_qt/configure_graphics.h" +#include "ui_configure_graphics.h" + +#include "core/settings.h" + +ConfigureGraphics::ConfigureGraphics(QWidget *parent) : + QWidget(parent), + ui(new Ui::ConfigureGraphics) +{ + ui->setupUi(this); + this->setConfiguration(); +} + +ConfigureGraphics::~ConfigureGraphics() { +} + +void ConfigureGraphics::setConfiguration() { + ui->toogle_hw_renderer->setChecked(Settings::values.use_hw_renderer); + ui->toogle_shader_jit->setChecked(Settings::values.use_shader_jit); + ui->toogle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution); +} + +void ConfigureGraphics::applyConfiguration() { + Settings::values.use_hw_renderer = ui->toogle_hw_renderer->isChecked(); + Settings::values.use_shader_jit = ui->toogle_shader_jit->isChecked(); + Settings::values.use_scaled_resolution = ui->toogle_scaled_resolution->isChecked(); + Settings::Apply(); +} diff --git a/src/citra_qt/configure_graphics.h b/src/citra_qt/configure_graphics.h new file mode 100644 index 000000000..dfb0c0461 --- /dev/null +++ b/src/citra_qt/configure_graphics.h @@ -0,0 +1,29 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +namespace Ui { +class ConfigureGraphics; +} + +class ConfigureGraphics : public QWidget +{ + Q_OBJECT + +public: + explicit ConfigureGraphics(QWidget *parent = nullptr); + ~ConfigureGraphics(); + + void applyConfiguration(); + +private: + void setConfiguration(); + +private: + std::unique_ptr ui; +}; diff --git a/src/citra_qt/configure_graphics.ui b/src/citra_qt/configure_graphics.ui new file mode 100644 index 000000000..336d49b19 --- /dev/null +++ b/src/citra_qt/configure_graphics.ui @@ -0,0 +1,85 @@ + + + ConfigureGraphics + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + Graphics + + + + + + Enable hardware renderer + + + + + + + Enable shader JIT + + + + + + + Enable scaled resolution + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + toogle_gdbstub + toggled(bool) + gdbport_spinbox + setEnabled(bool) + + + 84 + 157 + + + 342 + 158 + + + + + From 08ad9b36d44e3cca0802bb1198036c5d77c844cc Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 25 Aug 2016 18:20:47 -0400 Subject: [PATCH 65/77] config: Add a setting for graphics V-Sync. --- src/citra/config.cpp | 1 + src/citra/default_ini.h | 4 ++++ src/citra/emu_window/emu_window_sdl2.cpp | 1 + src/citra_qt/bootmanager.cpp | 1 + src/citra_qt/config.cpp | 2 ++ src/citra_qt/configure_graphics.cpp | 3 ++- src/citra_qt/configure_graphics.ui | 7 +++++++ src/core/settings.h | 1 + src/video_core/video_core.cpp | 1 + 9 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/citra/config.cpp b/src/citra/config.cpp index e832ec58d..d71045646 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -71,6 +71,7 @@ void Config::ReadValues() { Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true); Settings::values.use_shader_jit = sdl2_config->GetBoolean("Renderer", "use_shader_jit", true); Settings::values.use_scaled_resolution = sdl2_config->GetBoolean("Renderer", "use_scaled_resolution", false); + Settings::values.use_vsync = sdl2_config->GetBoolean("Renderer", "use_vsync", false); Settings::values.bg_red = (float)sdl2_config->GetReal("Renderer", "bg_red", 1.0); Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 1.0); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 6249ef9e2..b10700e62 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -55,6 +55,10 @@ use_shader_jit = # 0 (default): Native, 1: Scaled use_scaled_resolution = +# Whether to enable V-Sync (caps the framerate at 60FPS) or not. +# 0 (default): Off, 1: On +use_vsync = + # The clear color for the renderer. What shows up on the sides of the bottom screen. # Must be in range of 0.0-1.0. Defaults to 1.0 for all. bg_red = diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp index 591f68aa4..da12307b7 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra/emu_window/emu_window_sdl2.cpp @@ -108,6 +108,7 @@ EmuWindow_SDL2::EmuWindow_SDL2() { OnResize(); OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); SDL_PumpEvents(); + SDL_GL_SetSwapInterval(Settings::values.use_vsync); DoneCurrent(); } diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 414b2f8af..a9669c559 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -119,6 +119,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) : QGLFormat fmt; fmt.setVersion(3,3); fmt.setProfile(QGLFormat::CoreProfile); + fmt.setSwapInterval(VideoCore::g_vsync_enabled); // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X fmt.setOption(QGL::NoDeprecatedFunctions); diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 93c6a6e41..ff7af445e 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -48,6 +48,7 @@ void Config::ReadValues() { Settings::values.use_hw_renderer = qt_config->value("use_hw_renderer", true).toBool(); Settings::values.use_shader_jit = qt_config->value("use_shader_jit", true).toBool(); Settings::values.use_scaled_resolution = qt_config->value("use_scaled_resolution", false).toBool(); + Settings::values.use_vsync = qt_config->value("use_vsync", false).toBool(); Settings::values.bg_red = qt_config->value("bg_red", 1.0).toFloat(); Settings::values.bg_green = qt_config->value("bg_green", 1.0).toFloat(); @@ -139,6 +140,7 @@ void Config::SaveValues() { qt_config->setValue("use_hw_renderer", Settings::values.use_hw_renderer); qt_config->setValue("use_shader_jit", Settings::values.use_shader_jit); qt_config->setValue("use_scaled_resolution", Settings::values.use_scaled_resolution); + qt_config->setValue("use_vsync", Settings::values.use_vsync); // Cast to double because Qt's written float values are not human-readable qt_config->setValue("bg_red", (double)Settings::values.bg_red); diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configure_graphics.cpp index 85a120686..22def58d4 100644 --- a/src/citra_qt/configure_graphics.cpp +++ b/src/citra_qt/configure_graphics.cpp @@ -22,11 +22,12 @@ void ConfigureGraphics::setConfiguration() { ui->toogle_hw_renderer->setChecked(Settings::values.use_hw_renderer); ui->toogle_shader_jit->setChecked(Settings::values.use_shader_jit); ui->toogle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution); + ui->toogle_vsync->setChecked(Settings::values.use_vsync); } void ConfigureGraphics::applyConfiguration() { Settings::values.use_hw_renderer = ui->toogle_hw_renderer->isChecked(); Settings::values.use_shader_jit = ui->toogle_shader_jit->isChecked(); - Settings::values.use_scaled_resolution = ui->toogle_scaled_resolution->isChecked(); + Settings::values.use_vsync = ui->toogle_vsync->isChecked(); Settings::Apply(); } diff --git a/src/citra_qt/configure_graphics.ui b/src/citra_qt/configure_graphics.ui index 336d49b19..e68d68c0e 100644 --- a/src/citra_qt/configure_graphics.ui +++ b/src/citra_qt/configure_graphics.ui @@ -43,6 +43,13 @@ + + + + Enable V-Sync + + +
diff --git a/src/core/settings.h b/src/core/settings.h index f95e62390..34ff22f3f 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -72,6 +72,7 @@ struct Values { bool use_hw_renderer; bool use_shader_jit; bool use_scaled_resolution; + bool use_vsync; float bg_red; float bg_green; diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index c9975876d..bd6e5eb6b 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -22,6 +22,7 @@ std::unique_ptr g_renderer; ///< Renderer plugin std::atomic g_hw_renderer_enabled; std::atomic g_shader_jit_enabled; std::atomic g_scaled_resolution_enabled; +std::atomic g_vsync_enabled; /// Initialize the video core bool Init(EmuWindow* emu_window) { From 7299895b4833521ebf80cc8812c734382e60225f Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 29 Aug 2016 21:28:31 -0400 Subject: [PATCH 66/77] system: Add a function to see if the emulator is running. --- src/core/system.cpp | 10 ++++++++++ src/core/system.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/core/system.cpp b/src/core/system.cpp index 4a4757af3..4fc266cb0 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -17,6 +17,8 @@ namespace System { +static bool is_powered_on{ false }; + Result Init(EmuWindow* emu_window) { Core::Init(); CoreTiming::Init(); @@ -30,9 +32,15 @@ Result Init(EmuWindow* emu_window) { AudioCore::Init(); GDBStub::Init(); + is_powered_on = true; + return Result::Success; } +bool IsPoweredOn() { + return is_powered_on; +} + void Shutdown() { GDBStub::Shutdown(); AudioCore::Shutdown(); @@ -42,6 +50,8 @@ void Shutdown() { HW::Shutdown(); CoreTiming::Shutdown(); Core::Shutdown(); + + is_powered_on = false; } } // namespace diff --git a/src/core/system.h b/src/core/system.h index a4a627ea9..fb0ca4e1b 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -16,6 +16,7 @@ enum class Result { }; Result Init(EmuWindow* emu_window); +bool IsPoweredOn(); void Shutdown(); } From 02702c66052c10b10ba0a6af6ab34734886d3728 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 29 Aug 2016 21:28:58 -0400 Subject: [PATCH 67/77] qt: Recreate GL context on startup to support changing V-Sync. --- src/citra_qt/bootmanager.cpp | 60 +++++++++++++++++++++--------------- src/citra_qt/bootmanager.h | 2 ++ src/citra_qt/main.cpp | 2 ++ 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index a9669c559..6dddde9ba 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -107,37 +107,13 @@ private: }; GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) : - QWidget(parent), keyboard_id(0), emu_thread(emu_thread) { + QWidget(parent), keyboard_id(0), emu_thread(emu_thread), child(nullptr) { std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); setWindowTitle(QString::fromStdString(window_title)); keyboard_id = KeyMap::NewDeviceId(); ReloadSetKeymaps(); - - // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose - QGLFormat fmt; - fmt.setVersion(3,3); - fmt.setProfile(QGLFormat::CoreProfile); - fmt.setSwapInterval(VideoCore::g_vsync_enabled); - // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X - fmt.setOption(QGL::NoDeprecatedFunctions); - - child = new GGLWidgetInternal(fmt, this); - QBoxLayout* layout = new QHBoxLayout(this); - - resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); - layout->addWidget(child); - layout->setMargin(0); - setLayout(layout); - - OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); - - OnFramebufferSizeChanged(); - NotifyClientAreaSizeChanged(std::pair(child->width(), child->height())); - - BackupGeometry(); - } void GRenderWindow::moveContext() @@ -282,6 +258,40 @@ void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) NotifyClientAreaSizeChanged(std::make_pair(width, height)); } +void GRenderWindow::InitRenderTarget() { + if (child) { + delete child; + } + + if (layout()) { + delete layout(); + } + + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose + QGLFormat fmt; + fmt.setVersion(3, 3); + fmt.setProfile(QGLFormat::CoreProfile); + fmt.setSwapInterval(Settings::values.use_vsync); + + // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X + fmt.setOption(QGL::NoDeprecatedFunctions); + + child = new GGLWidgetInternal(fmt, this); + QBoxLayout* layout = new QHBoxLayout(this); + + resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); + layout->addWidget(child); + layout->setMargin(0); + setLayout(layout); + + OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); + + OnFramebufferSizeChanged(); + NotifyClientAreaSizeChanged(std::pair(child->width(), child->height())); + + BackupGeometry(); +} + void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair& minimal_size) { setMinimumSize(minimal_size.first, minimal_size.second); } diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 0dcf3e5eb..c1da2bc5f 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h @@ -126,6 +126,8 @@ public: void OnClientAreaResized(unsigned width, unsigned height); + void InitRenderTarget(); + public slots: void moveContext(); // overridden diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 68a936087..9fd4482f6 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -243,7 +243,9 @@ bool GMainWindow::InitializeSystem() { if (emu_thread != nullptr) ShutdownGame(); + render_window->InitRenderTarget(); render_window->MakeCurrent(); + if (!gladLoadGL()) { QMessageBox::critical(this, tr("Error while starting Citra!"), tr("Failed to initialize the video core!\n\n" From 74842116b287165d1db959437a439f13a17c724c Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 29 Aug 2016 21:29:58 -0400 Subject: [PATCH 68/77] qt: Add an option to settings for enabling V-Sync. --- src/citra_qt/configure_graphics.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configure_graphics.cpp index 22def58d4..9c3ae1cbd 100644 --- a/src/citra_qt/configure_graphics.cpp +++ b/src/citra_qt/configure_graphics.cpp @@ -6,6 +6,7 @@ #include "ui_configure_graphics.h" #include "core/settings.h" +#include "core/system.h" ConfigureGraphics::ConfigureGraphics(QWidget *parent) : QWidget(parent), @@ -13,6 +14,8 @@ ConfigureGraphics::ConfigureGraphics(QWidget *parent) : { ui->setupUi(this); this->setConfiguration(); + + ui->toogle_vsync->setEnabled(!System::IsPoweredOn()); } ConfigureGraphics::~ConfigureGraphics() { @@ -28,6 +31,7 @@ void ConfigureGraphics::setConfiguration() { void ConfigureGraphics::applyConfiguration() { Settings::values.use_hw_renderer = ui->toogle_hw_renderer->isChecked(); Settings::values.use_shader_jit = ui->toogle_shader_jit->isChecked(); + Settings::values.use_scaled_resolution = ui->toogle_scaled_resolution->isChecked(); Settings::values.use_vsync = ui->toogle_vsync->isChecked(); Settings::Apply(); } From 7a79fa7a90ccdc669f7af2b1f5dbf6ad1df31cb4 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 30 Aug 2016 19:30:13 +0200 Subject: [PATCH 69/77] OpenGL: Avoid error on unsupported lighting LUT --- src/video_core/renderer_opengl/gl_shader_gen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 36513dedc..3de372f67 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -400,6 +400,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { default: LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input); UNIMPLEMENTED(); + index = "0.0"; break; } From 0ef4185644def3e7d99d88af3c8dd27d40660c82 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Wed, 31 Aug 2016 16:55:10 +0100 Subject: [PATCH 70/77] sink: Change EnqueueSamples to take a pointer to a buffer instead of a std::vector --- src/audio_core/hle/dsp.cpp | 3 ++- src/audio_core/null_sink.h | 2 +- src/audio_core/sdl2_sink.cpp | 6 ++---- src/audio_core/sdl2_sink.h | 2 +- src/audio_core/sink.h | 5 +++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp index 0640e1eff..a195bc74c 100644 --- a/src/audio_core/hle/dsp.cpp +++ b/src/audio_core/hle/dsp.cpp @@ -90,7 +90,8 @@ static AudioCore::TimeStretcher time_stretcher; static void OutputCurrentFrame(const StereoFrame16& frame) { time_stretcher.AddSamples(&frame[0][0], frame.size()); - sink->EnqueueSamples(time_stretcher.Process(sink->SamplesInQueue())); + std::vector stretched_samples = time_stretcher.Process(sink->SamplesInQueue()); + sink->EnqueueSamples(stretched_samples.data(), stretched_samples.size() / 2); } // Public Interface diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h index faf0ee4e1..9931c4778 100644 --- a/src/audio_core/null_sink.h +++ b/src/audio_core/null_sink.h @@ -19,7 +19,7 @@ public: return native_sample_rate; } - void EnqueueSamples(const std::vector&) override {} + void EnqueueSamples(const s16*, size_t) override {} size_t SamplesInQueue() const override { return 0; diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp index dc75c04ee..311dd5b59 100644 --- a/src/audio_core/sdl2_sink.cpp +++ b/src/audio_core/sdl2_sink.cpp @@ -71,14 +71,12 @@ unsigned int SDL2Sink::GetNativeSampleRate() const { return impl->sample_rate; } -void SDL2Sink::EnqueueSamples(const std::vector& samples) { +void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) { if (impl->audio_device_id <= 0) return; - ASSERT_MSG(samples.size() % 2 == 0, "Samples must be in interleaved stereo PCM16 format (size must be a multiple of two)"); - SDL_LockAudioDevice(impl->audio_device_id); - impl->queue.emplace_back(samples); + impl->queue.emplace_back(samples, samples + sample_count * 2); SDL_UnlockAudioDevice(impl->audio_device_id); } diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h index 0f296b673..b13827214 100644 --- a/src/audio_core/sdl2_sink.h +++ b/src/audio_core/sdl2_sink.h @@ -18,7 +18,7 @@ public: unsigned int GetNativeSampleRate() const override; - void EnqueueSamples(const std::vector& samples) override; + void EnqueueSamples(const s16* samples, size_t sample_count) override; size_t SamplesInQueue() const override; diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h index 1c881c3d2..a06fc3dcc 100644 --- a/src/audio_core/sink.h +++ b/src/audio_core/sink.h @@ -23,9 +23,10 @@ public: /** * Feed stereo samples to sink. - * @param samples Samples in interleaved stereo PCM16 format. Size of vector must be multiple of two. + * @param samples Samples in interleaved stereo PCM16 format. + * @param sample_count Number of samples. */ - virtual void EnqueueSamples(const std::vector& samples) = 0; + virtual void EnqueueSamples(const s16* samples, size_t sample_count) = 0; /// Samples enqueued that have not been played yet. virtual std::size_t SamplesInQueue() const = 0; From 904a31969469a5ecff7eacfddc8541ea5996dcdf Mon Sep 17 00:00:00 2001 From: MerryMage Date: Wed, 31 Aug 2016 16:56:30 +0100 Subject: [PATCH 71/77] audio_core: Add EnableStretching to interface so that one can toggle stretching on and off --- src/audio_core/audio_core.cpp | 4 +++ src/audio_core/audio_core.h | 3 +++ src/audio_core/hle/dsp.cpp | 46 ++++++++++++++++++++++++++++------- src/audio_core/hle/dsp.h | 8 ++++++ 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp index d42249ebd..8e19ec0c4 100644 --- a/src/audio_core/audio_core.cpp +++ b/src/audio_core/audio_core.cpp @@ -71,6 +71,10 @@ void SelectSink(std::string sink_id) { DSP::HLE::SetSink(iter->factory()); } +void EnableStretching(bool enable) { + DSP::HLE::EnableStretching(enable); +} + void Shutdown() { CoreTiming::UnscheduleEvent(tick_event, 0); DSP::HLE::Shutdown(); diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h index f618361f3..7e678aba5 100644 --- a/src/audio_core/audio_core.h +++ b/src/audio_core/audio_core.h @@ -23,6 +23,9 @@ void AddAddressSpace(Kernel::VMManager& vm_manager); /// Select the sink to use based on sink id. void SelectSink(std::string sink_id); +/// Enable/Disable stretching. +void EnableStretching(bool enable); + /// Shutdown Audio Core void Shutdown(); diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp index a195bc74c..0cddeb82a 100644 --- a/src/audio_core/hle/dsp.cpp +++ b/src/audio_core/hle/dsp.cpp @@ -85,13 +85,45 @@ static StereoFrame16 GenerateCurrentFrame() { // Audio output +static bool perform_time_stretching = true; static std::unique_ptr sink; static AudioCore::TimeStretcher time_stretcher; +static void FlushResidualStretcherAudio() { + time_stretcher.Flush(); + while (true) { + std::vector residual_audio = time_stretcher.Process(sink->SamplesInQueue()); + if (residual_audio.empty()) + break; + sink->EnqueueSamples(residual_audio.data(), residual_audio.size() / 2); + } +} + static void OutputCurrentFrame(const StereoFrame16& frame) { - time_stretcher.AddSamples(&frame[0][0], frame.size()); - std::vector stretched_samples = time_stretcher.Process(sink->SamplesInQueue()); - sink->EnqueueSamples(stretched_samples.data(), stretched_samples.size() / 2); + if (perform_time_stretching) { + time_stretcher.AddSamples(&frame[0][0], frame.size()); + std::vector stretched_samples = time_stretcher.Process(sink->SamplesInQueue()); + sink->EnqueueSamples(stretched_samples.data(), stretched_samples.size() / 2); + } else { + constexpr size_t maximum_sample_latency = 1024; // about 32 miliseconds + if (sink->SamplesInQueue() > maximum_sample_latency) { + // This can occur if we're running too fast and samples are starting to back up. + // Just drop the samples. + return; + } + + sink->EnqueueSamples(&frame[0][0], frame.size()); + } +} + +void EnableStretching(bool enable) { + if (perform_time_stretching == enable) + return; + + if (!enable) { + FlushResidualStretcherAudio(); + } + perform_time_stretching = enable; } // Public Interface @@ -112,12 +144,8 @@ void Init() { } void Shutdown() { - time_stretcher.Flush(); - while (true) { - std::vector residual_audio = time_stretcher.Process(sink->SamplesInQueue()); - if (residual_audio.empty()) - break; - sink->EnqueueSamples(residual_audio); + if (perform_time_stretching) { + FlushResidualStretcherAudio(); } } diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h index 9275cd7de..565f20b6f 100644 --- a/src/audio_core/hle/dsp.h +++ b/src/audio_core/hle/dsp.h @@ -544,5 +544,13 @@ bool Tick(); */ void SetSink(std::unique_ptr sink); +/** + * Enables/Disables audio-stretching. + * Audio stretching is an enhancement that stretches audio to match emulation + * speed to prevent stuttering at the cost of some audio latency. + * @param enable true to enable, false to disable. + */ +void EnableStretching(bool enable); + } // namespace HLE } // namespace DSP From dc3f6a34f8e3458982f3ad646a54bbeac4b918e2 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Wed, 31 Aug 2016 16:59:37 +0100 Subject: [PATCH 72/77] configure_audio: User-configuratble option to enable/disable audio stretching --- src/citra/config.cpp | 1 + src/citra/default_ini.h | 6 ++++++ src/citra_qt/config.cpp | 2 ++ src/citra_qt/configure_audio.cpp | 3 +++ src/citra_qt/configure_audio.ui | 10 ++++++++++ src/core/settings.cpp | 1 + src/core/settings.h | 1 + 7 files changed, 24 insertions(+) diff --git a/src/citra/config.cpp b/src/citra/config.cpp index e832ec58d..f48386b9c 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -78,6 +78,7 @@ void Config::ReadValues() { // Audio Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); + Settings::values.enable_audio_stretching = sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true); // Data Storage Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 6249ef9e2..5b8ca12a0 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -66,6 +66,12 @@ bg_green = # auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) output_engine = +# Whether or not to enable the audio-stretching post-processing effect. +# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter, +# at the cost of increasing audio latency. +# 0: No, 1 (default): Yes +enable_audio_stretching = + [Data Storage] # Whether to create a virtual SD card. # 1 (default): Yes, 0: No diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 93c6a6e41..ff3bfe1bd 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -56,6 +56,7 @@ void Config::ReadValues() { qt_config->beginGroup("Audio"); Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); + Settings::values.enable_audio_stretching = qt_config->value("enable_audio_stretching", true).toBool(); qt_config->endGroup(); qt_config->beginGroup("Data Storage"); @@ -148,6 +149,7 @@ void Config::SaveValues() { qt_config->beginGroup("Audio"); qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); + qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching); qt_config->endGroup(); qt_config->beginGroup("Data Storage"); diff --git a/src/citra_qt/configure_audio.cpp b/src/citra_qt/configure_audio.cpp index cedfa2f2a..7100be158 100644 --- a/src/citra_qt/configure_audio.cpp +++ b/src/citra_qt/configure_audio.cpp @@ -36,9 +36,12 @@ void ConfigureAudio::setConfiguration() { } } ui->output_sink_combo_box->setCurrentIndex(new_sink_index); + + ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching); } void ConfigureAudio::applyConfiguration() { Settings::values.sink_id = ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()).toStdString(); + Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked(); Settings::Apply(); } diff --git a/src/citra_qt/configure_audio.ui b/src/citra_qt/configure_audio.ui index d7f6946ca..3e2b4635f 100644 --- a/src/citra_qt/configure_audio.ui +++ b/src/citra_qt/configure_audio.ui @@ -25,6 +25,16 @@ + + + + Enable audio stretching + + + This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. + + +
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 77261eafe..1b6733a79 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -24,6 +24,7 @@ void Apply() { VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution; AudioCore::SelectSink(values.sink_id); + AudioCore::EnableStretching(values.enable_audio_stretching); } diff --git a/src/core/settings.h b/src/core/settings.h index f95e62390..0962a4ecf 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -81,6 +81,7 @@ struct Values { // Audio std::string sink_id; + bool enable_audio_stretching; // Debugging bool use_gdbstub; From a71013cf16668a8d781a890823b6f6f203b865e9 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 31 Aug 2016 22:12:20 -0400 Subject: [PATCH 73/77] qt: Rename all "toogle" to "toggle". --- src/citra_qt/configure_debug.cpp | 4 ++-- src/citra_qt/configure_debug.ui | 4 ++-- src/citra_qt/configure_general.cpp | 8 ++++---- src/citra_qt/configure_general.ui | 4 ++-- src/citra_qt/configure_graphics.cpp | 18 +++++++++--------- src/citra_qt/configure_graphics.ui | 10 +++++----- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/citra_qt/configure_debug.cpp b/src/citra_qt/configure_debug.cpp index dc3d7b906..fa57a7f72 100644 --- a/src/citra_qt/configure_debug.cpp +++ b/src/citra_qt/configure_debug.cpp @@ -19,13 +19,13 @@ ConfigureDebug::~ConfigureDebug() { } void ConfigureDebug::setConfiguration() { - ui->toogle_gdbstub->setChecked(Settings::values.use_gdbstub); + ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub); ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub); ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port); } void ConfigureDebug::applyConfiguration() { - Settings::values.use_gdbstub = ui->toogle_gdbstub->isChecked(); + Settings::values.use_gdbstub = ui->toggle_gdbstub->isChecked(); Settings::values.gdbstub_port = ui->gdbport_spinbox->value(); Settings::Apply(); } diff --git a/src/citra_qt/configure_debug.ui b/src/citra_qt/configure_debug.ui index 3ba7f44da..bbbb0e3f4 100644 --- a/src/citra_qt/configure_debug.ui +++ b/src/citra_qt/configure_debug.ui @@ -25,7 +25,7 @@ - + Enable GDB Stub @@ -83,7 +83,7 @@ - toogle_gdbstub + toggle_gdbstub toggled(bool) gdbport_spinbox setEnabled(bool) diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp index 3e7a91885..95aab9f2e 100644 --- a/src/citra_qt/configure_general.cpp +++ b/src/citra_qt/configure_general.cpp @@ -20,14 +20,14 @@ ConfigureGeneral::~ConfigureGeneral() { } void ConfigureGeneral::setConfiguration() { - ui->toogle_deepscan->setChecked(UISettings::values.gamedir_deepscan); - ui->toogle_check_exit->setChecked(UISettings::values.confirm_before_closing); + ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan); + ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); ui->region_combobox->setCurrentIndex(Settings::values.region_value); } void ConfigureGeneral::applyConfiguration() { - UISettings::values.gamedir_deepscan = ui->toogle_deepscan->isChecked(); - UISettings::values.confirm_before_closing = ui->toogle_check_exit->isChecked(); + UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); + UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); Settings::values.region_value = ui->region_combobox->currentIndex(); Settings::Apply(); } diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configure_general.ui index f993f7525..343f804c0 100644 --- a/src/citra_qt/configure_general.ui +++ b/src/citra_qt/configure_general.ui @@ -25,14 +25,14 @@ - + Recursive scan for game folder - + Confirm exit while emulation is running diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configure_graphics.cpp index 9c3ae1cbd..5a8101795 100644 --- a/src/citra_qt/configure_graphics.cpp +++ b/src/citra_qt/configure_graphics.cpp @@ -15,23 +15,23 @@ ConfigureGraphics::ConfigureGraphics(QWidget *parent) : ui->setupUi(this); this->setConfiguration(); - ui->toogle_vsync->setEnabled(!System::IsPoweredOn()); + ui->toggle_vsync->setEnabled(!System::IsPoweredOn()); } ConfigureGraphics::~ConfigureGraphics() { } void ConfigureGraphics::setConfiguration() { - ui->toogle_hw_renderer->setChecked(Settings::values.use_hw_renderer); - ui->toogle_shader_jit->setChecked(Settings::values.use_shader_jit); - ui->toogle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution); - ui->toogle_vsync->setChecked(Settings::values.use_vsync); + ui->toggle_hw_renderer->setChecked(Settings::values.use_hw_renderer); + ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit); + ui->toggle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution); + ui->toggle_vsync->setChecked(Settings::values.use_vsync); } void ConfigureGraphics::applyConfiguration() { - Settings::values.use_hw_renderer = ui->toogle_hw_renderer->isChecked(); - Settings::values.use_shader_jit = ui->toogle_shader_jit->isChecked(); - Settings::values.use_scaled_resolution = ui->toogle_scaled_resolution->isChecked(); - Settings::values.use_vsync = ui->toogle_vsync->isChecked(); + Settings::values.use_hw_renderer = ui->toggle_hw_renderer->isChecked(); + Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked(); + Settings::values.use_scaled_resolution = ui->toggle_scaled_resolution->isChecked(); + Settings::values.use_vsync = ui->toggle_vsync->isChecked(); Settings::Apply(); } diff --git a/src/citra_qt/configure_graphics.ui b/src/citra_qt/configure_graphics.ui index e68d68c0e..da6e19ce1 100644 --- a/src/citra_qt/configure_graphics.ui +++ b/src/citra_qt/configure_graphics.ui @@ -23,28 +23,28 @@ - + Enable hardware renderer - + Enable shader JIT - + Enable scaled resolution - + Enable V-Sync @@ -73,7 +73,7 @@ - toogle_gdbstub + toggle_gdbstub toggled(bool) gdbport_spinbox setEnabled(bool) From 8b685c430857e94937c49d73a406b0cb2119d587 Mon Sep 17 00:00:00 2001 From: James Rowe Date: Wed, 31 Aug 2016 20:45:29 -0600 Subject: [PATCH 74/77] MSVC: Add RelWithDebInfo and removing debugging from Release. This should reduce build size on windows from roughly 12MB compressed to 7MB --- CMakeLists.txt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ac3df0e0..d9282ed58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ else() # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) - set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE) + set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE STRING "" FORCE) # Tweak optimization settings # As far as I can tell, there's no way to override the CMake defaults while leaving user @@ -85,24 +85,28 @@ else() # /W3 - Level 3 warnings # /MP - Multi-threaded compilation - # /Zi - Output debugging information - # /Zo - enahnced debug info for optimized builds - set(CMAKE_C_FLAGS "/W3 /MP /Zi /Zo" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS "/W3 /MP" CACHE STRING "" FORCE) # /EHsc - C++-only exception handling semantics set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} /EHsc" CACHE STRING "" FORCE) # /MDd - Multi-threaded Debug Runtime DLL - set(CMAKE_C_FLAGS_DEBUG "/Od /MDd" CACHE STRING "" FORCE) + # /Zi - Output debugging information + set(CMAKE_C_FLAGS_DEBUG "/Od /MDd /Zi" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "" FORCE) # /O2 - Optimization level 2 # /GS- - No stack buffer overflow checks # /MD - Multi-threaded runtime DLL - set(CMAKE_C_FLAGS_RELEASE "/O2 /GS- /MD" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_RELEASE "/O2 /GS- /MD" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "" FORCE) + # /Zo - enahnced debug info for optimized builds + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} /Zo /Zi" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}" CACHE STRING "" FORCE) + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG ${CMAKE_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING "" FORCE) endif() add_definitions(-DSINGLETHREADED) From d3619aaff3e1af4b536e453df28c54f426a3cb21 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Thu, 1 Sep 2016 14:39:20 +0100 Subject: [PATCH 75/77] appveyor: Remove tests.exe and tests.pdb from archive --- appveyor.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 28c902bee..898690faa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,6 +43,10 @@ on_success: # Where are these spaces coming from? Regardless, let's remove them $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" $BUILD_NAME_NOQT = "citra-noqt-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" + + # Remove unnecessary files + rm .\build\bin\release\*tests* + # Zip up the build folder and documentation 7z a $BUILD_NAME .\build\bin\release\* .\license.txt .\README.md # Do a second archive with only the binaries (excludes dlls) and documentation From 93bcd00e44f42757307cf76ef7c810637ac9dd85 Mon Sep 17 00:00:00 2001 From: James Rowe Date: Thu, 1 Sep 2016 10:47:31 -0600 Subject: [PATCH 76/77] Create a separate archive for debugsymbols on windows This reduces the main download size and uploads the symbols to a different directory --- appveyor.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 898690faa..0ffb680ff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -42,11 +42,16 @@ on_success: $GITREV = $(git show -s --format='%h') # Where are these spaces coming from? Regardless, let's remove them $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" + $BUILD_NAME_PDB = "citra-${GITDATE}-${GITREV}-windows-amd64-debugsymbols.7z" -replace " ","" $BUILD_NAME_NOQT = "citra-noqt-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" # Remove unnecessary files rm .\build\bin\release\*tests* + # Put the pdb files in a separate archive and remove them from the main download + 7z a $BUILD_NAME_PDB .\build\bin\release\*.pdb + rm .\build\bin\release\*.pdb + # Zip up the build folder and documentation 7z a $BUILD_NAME .\build\bin\release\* .\license.txt .\README.md # Do a second archive with only the binaries (excludes dlls) and documentation @@ -61,5 +66,6 @@ on_success: "open sftp://citra-builds:${env:BUILD_PASSWORD}@builds.citra-emu.org -hostkey=*" ` "put $BUILD_NAME /citra/nightly/windows-amd64/" ` "put $BUILD_NAME_NOQT /citra/nightly/windows-noqt-amd64/" ` + "put $BUILD_NAME_PDB /citra/nightly/windows-amd64-debugsymbols/" ` "exit" } From a71d6cc04078252768e4af07bc5d08c7f42b63fd Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Sep 2016 17:06:34 -0400 Subject: [PATCH 77/77] Revert "MSVC: Add RelWithDebInfo and removing debugging from Release." --- CMakeLists.txt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d9282ed58..6ac3df0e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ else() # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) - set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE STRING "" FORCE) + set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE) # Tweak optimization settings # As far as I can tell, there's no way to override the CMake defaults while leaving user @@ -85,28 +85,24 @@ else() # /W3 - Level 3 warnings # /MP - Multi-threaded compilation - set(CMAKE_C_FLAGS "/W3 /MP" CACHE STRING "" FORCE) + # /Zi - Output debugging information + # /Zo - enahnced debug info for optimized builds + set(CMAKE_C_FLAGS "/W3 /MP /Zi /Zo" CACHE STRING "" FORCE) # /EHsc - C++-only exception handling semantics set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} /EHsc" CACHE STRING "" FORCE) # /MDd - Multi-threaded Debug Runtime DLL - # /Zi - Output debugging information - set(CMAKE_C_FLAGS_DEBUG "/Od /MDd /Zi" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_DEBUG "/Od /MDd" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "" FORCE) # /O2 - Optimization level 2 # /GS- - No stack buffer overflow checks # /MD - Multi-threaded runtime DLL - set(CMAKE_C_FLAGS_RELEASE "/O2 /GS- /MD" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_RELEASE "/O2 /GS- /MD" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "" FORCE) - # /Zo - enahnced debug info for optimized builds - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} /Zo /Zi" CACHE STRING "" FORCE) - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}" CACHE STRING "" FORCE) - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) - set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG ${CMAKE_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING "" FORCE) + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) endif() add_definitions(-DSINGLETHREADED)