diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 90385653f7..a9535a1799 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -14,6 +14,7 @@ set(SRCS BreakPoints.cpp MsgHandler.cpp NandPaths.cpp Network.cpp + PcapFile.cpp SettingsHandler.cpp SDCardUtil.cpp StringUtil.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 00bcb07c80..87c14c321c 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -78,6 +78,7 @@ + @@ -114,6 +115,7 @@ + diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index 5f9b211828..bca6b0c68e 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -39,6 +39,7 @@ + @@ -86,6 +87,7 @@ + diff --git a/Source/Core/Common/PcapFile.cpp b/Source/Core/Common/PcapFile.cpp new file mode 100644 index 0000000000..9a28daca2d --- /dev/null +++ b/Source/Core/Common/PcapFile.cpp @@ -0,0 +1,66 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "Common/CommonTypes.h" +#include "Common/FileUtil.h" +#include "Common/PcapFile.h" + +namespace { + +const u32 PCAP_MAGIC = 0xa1b2c3d4; +const u16 PCAP_VERSION_MAJOR = 2; +const u16 PCAP_VERSION_MINOR = 4; +const u32 PCAP_CAPTURE_LENGTH = 65535; + +// TODO(delroth): Make this configurable at PCAP creation time? +const u32 PCAP_DATA_LINK_TYPE = 147; // Reserved for internal use. + +// Designed to be directly written into the PCAP file. The PCAP format is +// endian independent, so this works just fine. +#pragma pack(push, 1) +struct PCAPHeader +{ + u32 magic_number; + u16 version_major; + u16 version_minor; + s32 tz_offset; // Offset in seconds from the GMT timezone. + u32 ts_accuracy; // In practice, 0. + u32 capture_length; // Size at which we truncate packets. + u32 data_link_type; +}; + +struct PCAPRecordHeader +{ + u32 ts_sec; + u32 ts_usec; + u32 size_in_file; // Size after eventual truncation. + u32 real_size; // Size before eventual truncation. +}; +#pragma pack(pop) + +} // namespace + +void PCAP::AddHeader() +{ + PCAPHeader hdr = { + PCAP_MAGIC, PCAP_VERSION_MAJOR, PCAP_VERSION_MINOR, + 0, 0, PCAP_CAPTURE_LENGTH, PCAP_DATA_LINK_TYPE + }; + m_fp->WriteBytes(&hdr, sizeof (hdr)); +} + +void PCAP::AddPacket(const u8* bytes, size_t size) +{ + std::chrono::system_clock::time_point now(std::chrono::system_clock::now()); + auto ts = now.time_since_epoch(); + PCAPRecordHeader rec_hdr = { + (u32)std::chrono::duration_cast(ts).count(), + (u32)(std::chrono::duration_cast(ts).count() % 1000000), + (u32)size, (u32)size + }; + m_fp->WriteBytes(&rec_hdr, sizeof (rec_hdr)); + m_fp->WriteBytes(bytes, size); +} diff --git a/Source/Core/Common/PcapFile.h b/Source/Core/Common/PcapFile.h new file mode 100644 index 0000000000..f3bc98d23c --- /dev/null +++ b/Source/Core/Common/PcapFile.h @@ -0,0 +1,44 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +// PCAP is a standard file format for network capture files. This also extends +// to any capture of packetized intercommunication data. This file provides a +// class called PCAP which is a very light wrapper around the file format, +// allowing only creating a new PCAP capture file and appending packets to it. +// +// Example use: +// PCAP pcap(new IOFile("test.pcap", "wb")); +// pcap.AddPacket(pkt); // pkt is automatically casted to u8* + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/FileUtil.h" + +class PCAP final : public NonCopyable +{ +public: + // Takes ownership of the file object. Assumes the file object is already + // opened in write mode. + explicit PCAP(File::IOFile* fp) : m_fp(fp) + { + AddHeader(); + } + + template + void AddPacket(const T& obj) + { + AddPacket(reinterpret_cast(&obj), sizeof (obj)); + } + + void AddPacket(const u8* bytes, size_t size); + +private: + void AddHeader(); + + std::unique_ptr m_fp; +}; diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 62e7de4420..2a4915db45 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRCS ActionReplay.cpp DSP/DSPAssembler.cpp DSP/DSPDisassembler.cpp DSP/DSPAccelerator.cpp + DSP/DSPCaptureLogger.cpp DSP/DSPIntCCUtil.cpp DSP/DSPIntExtOps.cpp DSP/DSPHWInterface.cpp diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 5f9c6ce479..727b1b1f91 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -326,6 +326,7 @@ void SConfig::SaveDSPSettings(IniFile& ini) dsp->Set("DumpAudio", m_DumpAudio); dsp->Set("Backend", sBackend); dsp->Set("Volume", m_Volume); + dsp->Set("CaptureLog", m_DSPCaptureLog); } void SConfig::SaveFifoPlayerSettings(IniFile& ini) @@ -552,6 +553,7 @@ void SConfig::LoadDSPSettings(IniFile& ini) dsp->Get("Backend", &sBackend, BACKEND_NULLSOUND); #endif dsp->Get("Volume", &m_Volume, 100); + dsp->Get("CaptureLog", &m_DSPCaptureLog, false); } void SConfig::LoadFifoPlayerSettings(IniFile& ini) diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 0bda4cc132..45139caa71 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -92,6 +92,7 @@ struct SConfig : NonCopyable // DSP settings bool m_DSPEnableJIT; + bool m_DSPCaptureLog; bool m_DumpAudio; int m_Volume; std::string sBackend; diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 784e7503bd..0ea27a1b7e 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -64,6 +64,7 @@ + @@ -268,6 +269,7 @@ + @@ -468,4 +470,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index f25fbe6248..469b7783be 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -515,6 +515,9 @@ DSPCore + + DSPCore + DSPCore @@ -1041,6 +1044,9 @@ DSPCore + + DSPCore + DSPCore @@ -1205,4 +1211,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Core/DSP/DSPCaptureLogger.cpp b/Source/Core/Core/DSP/DSPCaptureLogger.cpp new file mode 100644 index 0000000000..b440d0c84d --- /dev/null +++ b/Source/Core/Core/DSP/DSPCaptureLogger.cpp @@ -0,0 +1,79 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "Common/CommonTypes.h" +#include "Common/FileUtil.h" +#include "Common/PcapFile.h" + +#include "Core/DSP/DSPCaptureLogger.h" + +// Definition of the packet structures stored in PCAP capture files. + +const u8 IFX_ACCESS_PACKET_MAGIC = 0; +const u8 DMA_PACKET_MAGIC = 1; + +#pragma pack(push, 1) +struct IFXAccessPacket +{ + u8 magic; // IFX_ACCESS_PACKET_MAGIC + u8 is_read; // 0 for writes, 1 for reads. + u16 address; + u16 value; +}; + +// Followed by the bytes of the DMA. +struct DMAPacket +{ + u8 magic; // DMA_PACKET_MAGIC + u16 dma_control; // Value of the DMA control register. + u32 gc_address; // Address in the GC RAM. + u16 dsp_address; // Address in the DSP RAM. + u16 length; // Length in bytes. +}; +#pragma pack(pop) + +PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(const std::string& pcap_filename) + : m_pcap(new PCAP(new File::IOFile(pcap_filename, "wb"))) +{ +} + +PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(PCAP* pcap) : m_pcap(pcap) +{ +} + +PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(std::unique_ptr&& pcap) + : m_pcap(std::move(pcap)) +{ +} + +void PCAPDSPCaptureLogger::LogIFXAccess(bool read, u16 address, u16 value) +{ + IFXAccessPacket pkt; + pkt.magic = IFX_ACCESS_PACKET_MAGIC; + pkt.is_read = !!read; // Make sure we actually have 0/1. + pkt.address = address; + pkt.value = value; + + m_pcap->AddPacket(pkt); +} + +void PCAPDSPCaptureLogger::LogDMA(u16 control, u32 gc_address, u16 dsp_address, + u16 length, const u8* data) +{ + // The length of a DMA cannot be above 64K, so we use a static buffer for + // the construction of the packet. + static u8 buffer[0x10000]; + + DMAPacket* pkt = reinterpret_cast(&buffer[0]); + pkt->magic = DMA_PACKET_MAGIC; + pkt->dma_control = control; + pkt->gc_address = gc_address; + pkt->dsp_address = dsp_address; + pkt->length = length; + memcpy(&buffer[sizeof (DMAPacket)], data, length); + + m_pcap->AddPacket(buffer, sizeof (DMAPacket) + length); +} diff --git a/Source/Core/Core/DSP/DSPCaptureLogger.h b/Source/Core/Core/DSP/DSPCaptureLogger.h new file mode 100644 index 0000000000..16406d4775 --- /dev/null +++ b/Source/Core/Core/DSP/DSPCaptureLogger.h @@ -0,0 +1,76 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/Common.h" + +class PCAP; + +// An interface used to capture and log structured data about internal DSP +// data transfers. +// +// Note: these calls are done within the DSP emulator in critical paths and at +// a high frequency. Implementations must try and avoid blocking for too long. +class DSPCaptureLogger +{ +public: + // Accesses (reads or writes) to memory mapped registers (external + // interface, also known as IFX). These are always 16 bits accesses. + virtual void LogIFXRead(u16 address, u16 read_value) = 0; + virtual void LogIFXWrite(u16 address, u16 written_value) = 0; + + // DMAs to/from main memory from/to DSP memory. We let the interpretation + // of the "control" field to the layer that analyze the logs and do not + // perform our own interpretation of it. Thus there is only one call which + // is used for DRAM/IRAM in any direction (to/from DSP). + // + // Length is expressed in bytes, not DSP words. + virtual void LogDMA(u16 control, u32 gc_address, u16 dsp_address, + u16 length, const u8* data) = 0; +}; + +// A dummy implementation of a capture logger that does nothing. This is the +// default implementation used by the DSP emulator. +// +// Can also be inherited from if you want to only override part of the methods. +class DefaultDSPCaptureLogger : public DSPCaptureLogger +{ +public: + virtual void LogIFXRead(u16 address, u16 read_value) override {} + virtual void LogIFXWrite(u16 address, u16 written_value) override {} + virtual void LogDMA(u16 control, u32 gc_address, u16 dsp_address, + u16 length, const u8* data) override {} +}; + +// A capture logger implementation that logs to PCAP files in a custom +// packet-based format. +class PCAPDSPCaptureLogger final : public DSPCaptureLogger, NonCopyable +{ +public: + // Automatically creates a writeable file (truncate existing file). + PCAPDSPCaptureLogger(const std::string& pcap_filename); + // Takes ownership of pcap. + PCAPDSPCaptureLogger(PCAP* pcap); + PCAPDSPCaptureLogger(std::unique_ptr&& pcap); + + virtual void LogIFXRead(u16 address, u16 read_value) override + { + LogIFXAccess(true, address, read_value); + } + virtual void LogIFXWrite(u16 address, u16 written_value) override + { + LogIFXAccess(false, address, written_value); + } + virtual void LogDMA(u16 control, u32 gc_address, u16 dsp_address, + u16 length, const u8* data) override; + +private: + void LogIFXAccess(bool read, u16 address, u16 value); + + std::unique_ptr m_pcap; +}; diff --git a/Source/Core/Core/DSP/DSPCore.cpp b/Source/Core/Core/DSP/DSPCore.cpp index 6cab6e48f5..dfa483ce47 100644 --- a/Source/Core/Core/DSP/DSPCore.cpp +++ b/Source/Core/Core/DSP/DSPCore.cpp @@ -42,40 +42,11 @@ DSPCoreState core_state = DSPCORE_STOP; u16 cyclesLeft = 0; bool init_hax = false; DSPEmitter *dspjit = nullptr; +std::unique_ptr g_dsp_cap; Common::Event step_event; -static bool LoadRom(const std::string& fname, int size_in_words, u16 *rom) -{ - File::IOFile pFile(fname, "rb"); - const size_t size_in_bytes = size_in_words * sizeof(u16); - if (pFile) - { - pFile.ReadArray(rom, size_in_words); - pFile.Close(); - - // Byteswap the rom. - for (int i = 0; i < size_in_words; i++) - rom[i] = Common::swap16(rom[i]); - - // Always keep ROMs write protected. - WriteProtectMemory(rom, size_in_bytes, false); - return true; - } - - PanicAlertT( - "Failed to load DSP ROM:\t%s\n" - "\n" - "This file is required to use DSP LLE.\n" - "It is not included with Dolphin as it contains copyrighted data.\n" - "Use DSPSpy to dump the file from your physical console.\n" - "\n" - "You may use the DSP HLE engine which does not require ROM dumps.\n" - "(Choose it from the \"Audio\" tab of the configuration dialog.)", fname.c_str()); - return false; -} - // Returns false if the hash fails and the user hits "Yes" -static bool VerifyRoms(const std::string& irom_filename, const std::string& coef_filename) +static bool VerifyRoms() { struct DspRomHashes { @@ -136,7 +107,7 @@ static void DSPCore_FreeMemoryPages() g_dsp.irom = g_dsp.iram = g_dsp.dram = g_dsp.coef = nullptr; } -bool DSPCore_Init(const std::string& irom_filename, const std::string& coef_filename, bool bUsingJIT) +bool DSPCore_Init(const DSPInitOptions& opts) { g_dsp.step_counter = 0; cyclesLeft = 0; @@ -148,14 +119,11 @@ bool DSPCore_Init(const std::string& irom_filename, const std::string& coef_file g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); - // Fill roms with zeros. - memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE); - memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE); + memcpy(g_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE); + memcpy(g_dsp.coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE); // Try to load real ROM contents. - if (!LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom) || - !LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef) || - !VerifyRoms(irom_filename, coef_filename)) + if (!VerifyRoms()) { DSPCore_FreeMemoryPages(); return false; @@ -201,9 +169,11 @@ bool DSPCore_Init(const std::string& irom_filename, const std::string& coef_file WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); // Initialize JIT, if necessary - if (bUsingJIT) + if (opts.core_type == DSPInitOptions::CORE_JIT) dspjit = new DSPEmitter(); + g_dsp_cap.reset(opts.capture_logger); + core_state = DSPCORE_RUNNING; return true; } @@ -220,6 +190,8 @@ void DSPCore_Shutdown() dspjit = nullptr; } DSPCore_FreeMemoryPages(); + + g_dsp_cap.reset(); } void DSPCore_Reset() diff --git a/Source/Core/Core/DSP/DSPCore.h b/Source/Core/Core/DSP/DSPCore.h index 31b8830c2d..eaffcc551f 100644 --- a/Source/Core/Core/DSP/DSPCore.h +++ b/Source/Core/Core/DSP/DSPCore.h @@ -25,11 +25,14 @@ #pragma once +#include +#include #include #include "Common/Thread.h" #include "Core/DSP/DSPBreakpoints.h" +#include "Core/DSP/DSPCaptureLogger.h" #include "Core/DSP/DSPEmitter.h" #define DSP_IRAM_BYTE_SIZE 0x2000 @@ -269,8 +272,39 @@ extern DSPBreakpoints dsp_breakpoints; extern DSPEmitter *dspjit; extern u16 cyclesLeft; extern bool init_hax; +extern std::unique_ptr g_dsp_cap; -bool DSPCore_Init(const std::string& irom_filename, const std::string& coef_filename, bool bUsingJIT); +struct DSPInitOptions +{ + // DSP IROM blob, which is where the DSP boots from. Embedded into the DSP. + std::array irom_contents; + + // DSP DROM blob, which contains resampling coefficients. + std::array coef_contents; + + // Core used to emulate the DSP. + // Default: CORE_JIT. + enum CoreType + { + CORE_INTERPRETER, + CORE_JIT, + }; + CoreType core_type; + + // Optional capture logger used to log internal DSP data transfers. + // Default: dummy implementation, does nothing. + DSPCaptureLogger* capture_logger; + + DSPInitOptions() + : core_type(CORE_JIT), + capture_logger(new DefaultDSPCaptureLogger()) + { + } +}; + +// Initializes the DSP emulator using the provided options. Takes ownership of +// all the pointers contained in the options structure. +bool DSPCore_Init(const DSPInitOptions& opts); void DSPCore_Reset(); void DSPCore_Shutdown(); // Frees all allocated memory. diff --git a/Source/Core/Core/DSP/DSPHWInterface.cpp b/Source/Core/Core/DSP/DSPHWInterface.cpp index 6125c3a414..163c776a61 100644 --- a/Source/Core/Core/DSP/DSPHWInterface.cpp +++ b/Source/Core/Core/DSP/DSPHWInterface.cpp @@ -115,6 +115,8 @@ u16 gdsp_mbox_read_l(u8 mbx) void gdsp_ifx_write(u32 addr, u32 val) { + g_dsp_cap->LogIFXWrite(addr, val); + switch (addr & 0xff) { case DSP_DIRQ: @@ -190,7 +192,7 @@ void gdsp_ifx_write(u32 addr, u32 val) } } -u16 gdsp_ifx_read(u16 addr) +static u16 _gdsp_ifx_read(u16 addr) { switch (addr & 0xff) { @@ -235,7 +237,14 @@ u16 gdsp_ifx_read(u16 addr) } } -static void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) +u16 gdsp_ifx_read(u16 addr) +{ + u16 retval = _gdsp_ifx_read(addr); + g_dsp_cap->LogIFXRead(addr, retval); + return retval; +} + +static const u8* gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) { UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); @@ -249,11 +258,15 @@ static void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) DSPHost::CodeLoaded((const u8*)g_dsp.iram + dsp_addr, size); NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc); + + return dst + dsp_addr; } -static void gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size) +static const u8* gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size) { ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); + + return nullptr; } #if _M_SSE >= 0x301 @@ -261,7 +274,7 @@ static const __m128i s_mask = _mm_set_epi32(0x0E0F0C0DL, 0x0A0B0809L, 0x06070405 #endif // TODO: These should eat clock cycles. -static void gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size) +static const u8* gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size) { u8* dst = ((u8*)g_dsp.dram); @@ -282,9 +295,11 @@ static void gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size) } } INFO_LOG(DSPLLE, "*** ddma_in RAM (0x%08x) -> DRAM_DSP (0x%04x) : size (0x%08x)", addr, dsp_addr / 2, size); + + return dst + dsp_addr; } -static void gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size) +static const u8* gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size) { const u8* src = ((const u8*)g_dsp.dram); @@ -306,6 +321,8 @@ static void gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size) } INFO_LOG(DSPLLE, "*** ddma_out DRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); + + return src + dsp_addr; } static void gdsp_do_dma() @@ -323,22 +340,28 @@ static void gdsp_do_dma() #if defined(_DEBUG) || defined(DEBUGFAST) DEBUG_LOG(DSPLLE, "DMA pc: %04x, Control: %04x, Address: %08x, DSP Address: %04x, Size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len); #endif + + const u8* copied_data_ptr; switch (ctl & 0x3) { case (DSP_CR_DMEM | DSP_CR_TO_CPU): - gdsp_ddma_out(dsp_addr, addr, len); + copied_data_ptr = gdsp_ddma_out(dsp_addr, addr, len); break; case (DSP_CR_DMEM | DSP_CR_FROM_CPU): - gdsp_ddma_in(dsp_addr, addr, len); + copied_data_ptr = gdsp_ddma_in(dsp_addr, addr, len); break; case (DSP_CR_IMEM | DSP_CR_TO_CPU): - gdsp_idma_out(dsp_addr, addr, len); + copied_data_ptr = gdsp_idma_out(dsp_addr, addr, len); break; case (DSP_CR_IMEM | DSP_CR_FROM_CPU): - gdsp_idma_in(dsp_addr, addr, len); + copied_data_ptr = gdsp_idma_in(dsp_addr, addr, len); break; } + + if (copied_data_ptr) + g_dsp_cap->LogDMA(ctl, addr, dsp_addr, len, copied_data_ptr); + } diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp index 8ada666527..516117a838 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp @@ -16,6 +16,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/Host.h" +#include "Core/DSP/DSPCaptureLogger.h" #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPDisassembler.h" #include "Core/DSP/DSPHost.h" @@ -108,11 +109,28 @@ void DSPLLE::dsp_thread(DSPLLE *dsp_lle) } } -bool DSPLLE::Initialize(void *hWnd, bool bWii, bool bDSPThread) +static bool LoadDSPRom(u16* rom, const std::string& filename, u32 size_in_bytes) { - m_bWii = bWii; - m_bDSPThread = bDSPThread; + std::string bytes; + if (!File::ReadFileToString(filename, bytes)) + return false; + if (bytes.size() != size_in_bytes) + { + ERROR_LOG(DSPLLE, "%s has a wrong size (%u, expected %u)", + filename.c_str(), (u32)bytes.size(), size_in_bytes); + return false; + } + + const u16* words = reinterpret_cast(bytes.c_str()); + for (u32 i = 0; i < size_in_bytes / 2; ++i) + rom[i] = Common::swap16(words[i]); + + return true; +} + +static bool FillDSPInitOptions(DSPInitOptions* opts) +{ std::string irom_file = File::GetUserPath(D_GCUSER_IDX) + DSP_IROM; std::string coef_file = File::GetUserPath(D_GCUSER_IDX) + DSP_COEF; @@ -121,8 +139,32 @@ bool DSPLLE::Initialize(void *hWnd, bool bWii, bool bDSPThread) if (!File::Exists(coef_file)) coef_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_COEF; - bool use_jit = SConfig::GetInstance().m_DSPEnableJIT; - if (!DSPCore_Init(irom_file, coef_file, use_jit)) + if (!LoadDSPRom(opts->irom_contents.data(), irom_file, DSP_IROM_BYTE_SIZE)) + return false; + if (!LoadDSPRom(opts->coef_contents.data(), coef_file, DSP_COEF_BYTE_SIZE)) + return false; + + opts->core_type = SConfig::GetInstance().m_DSPEnableJIT ? + DSPInitOptions::CORE_JIT : DSPInitOptions::CORE_INTERPRETER; + + if (SConfig::GetInstance().m_DSPCaptureLog) + { + const std::string pcap_path = File::GetUserPath(D_DUMPDSP_IDX) + "dsp.pcap"; + opts->capture_logger = new PCAPDSPCaptureLogger(pcap_path); + } + + return true; +} + +bool DSPLLE::Initialize(void *hWnd, bool bWii, bool bDSPThread) +{ + m_bWii = bWii; + m_bDSPThread = bDSPThread; + + DSPInitOptions opts; + if (!FillDSPInitOptions(&opts)) + return false; + if (!DSPCore_Init(opts)) return false; g_dsp.cpu_ram = Memory::GetPointer(0);