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);