diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 43542f5278..b73d036daf 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -583,7 +583,6 @@
-
@@ -993,6 +992,7 @@
+
true
true
@@ -1194,7 +1194,6 @@
-
@@ -1408,6 +1407,7 @@
+
true
true
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 39c329f066..e00f5b24ba 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -123,6 +123,9 @@
MIPS
+
+ MIPS
+
MIPS
@@ -1315,9 +1318,6 @@
HLE\Libraries
-
- MIPS
-
@@ -1350,6 +1350,9 @@
MIPS
+
+ MIPS
+
MIPS
@@ -2109,9 +2112,6 @@
HLE\Libraries
-
- MIPS
-
diff --git a/Core/MIPS/MIPSTracer.cpp b/Core/MIPS/MIPSTracer.cpp
new file mode 100644
index 0000000000..328e10645a
--- /dev/null
+++ b/Core/MIPS/MIPSTracer.cpp
@@ -0,0 +1,41 @@
+// Copyright (c) 2024- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "Core/MIPS/MIPSTracer.h"
+
+#include // for std::memcpy
+#include "Core/MIPS/MIPSTables.h" // for MIPSDisAsm
+
+
+bool TraceBlockStorage::push_block(u32* instructions, u32 size) {
+ if (cur_offset + size >= raw_instructions.size()) {
+ return false;
+ }
+ std::memcpy(cur_data_ptr, instructions, size);
+ cur_offset += size;
+ cur_data_ptr += size;
+ return true;
+}
+
+void TraceBlockStorage::initialize(u32 capacity) {
+ raw_instructions.resize(capacity);
+ cur_offset = 0;
+ cur_data_ptr = raw_instructions.data();
+}
+
+
+MIPSTracer mipsTracer;
diff --git a/Core/MIPS/MIPSTracer.h b/Core/MIPS/MIPSTracer.h
new file mode 100644
index 0000000000..15706c1c66
--- /dev/null
+++ b/Core/MIPS/MIPSTracer.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2024- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "Common/CommonTypes.h"
+#include "Core/Opcode.h"
+
+
+
+struct TraceBlockInfo {
+ u32 virt_address;
+ u32 size;
+ u32 storage_index;
+};
+
+struct TraceBlockStorage {
+ std::vector raw_instructions;
+ u32 cur_offset;
+ u32* cur_data_ptr;
+
+ TraceBlockStorage(u32 capacity):
+ raw_instructions(capacity, 0),
+ cur_offset(0),
+ cur_data_ptr(raw_instructions.data())
+ {}
+
+ TraceBlockStorage(): raw_instructions(), cur_offset(0), cur_data_ptr(nullptr) {}
+
+ bool push_block(u32* instructions, u32 size);
+
+ void initialize(u32 capacity);
+
+ Memory::Opcode operator[](u32 index) {
+ return Memory::Opcode(raw_instructions[index]);
+ }
+};
+
+
+template
+struct CyclicBuffer {
+ std::vector buffer;
+ u32 current_index;
+ bool overflow;
+
+ explicit CyclicBuffer(u32 capacity) : buffer(capacity, T()), current_index(0), overflow(false) {}
+
+ CyclicBuffer(): buffer(), current_index(0), overflow(false) {}
+
+ void push_back(const T& value);
+ void push_back(T&& value);
+
+ void clear();
+ void resize(u32 new_capacity);
+
+ std::vector get_content() const;
+};
+
+template
+std::vector CyclicBuffer::get_content() const {
+ if (!overflow) {
+ return std::vector(buffer.begin(), buffer.begin() + current_index);
+ }
+
+ std::vector ans;
+ ans.reserve(buffer.size());
+ std::copy(buffer.begin() + current_index, buffer.end(), std::back_inserter(ans));
+ std::copy(buffer.begin(), buffer.begin() + current_index, std::back_inserter(ans));
+ return ans;
+}
+
+template
+void CyclicBuffer::push_back(const T& value) {
+ buffer[current_index] = value;
+ ++current_index;
+ if (current_index == buffer.size()) {
+ current_index = 0;
+ overflow = true;
+ }
+}
+
+template
+void CyclicBuffer::push_back(T&& value) {
+ buffer[current_index] = std::move(value);
+ ++current_index;
+ if (current_index == buffer.size()) {
+ current_index = 0;
+ overflow = true;
+ }
+}
+
+template
+void CyclicBuffer::clear() {
+ buffer.clear();
+ current_index = 0;
+ overflow = false;
+}
+
+template
+void CyclicBuffer::resize(u32 new_capacity) {
+ buffer.resize(new_capacity);
+}
+
+struct MIPSTracer {
+ std::vector trace_info;
+
+ // The trace might be very big, in that case I don't mind losing the oldest entries.
+ CyclicBuffer executed_blocks;
+
+ std::unordered_map hash_to_index;
+
+ TraceBlockStorage storage;
+
+ std::string logging_path;
+
+ MIPSTracer(): trace_info(), executed_blocks(), hash_to_index(), storage(), logging_path() {}
+};
+
+extern MIPSTracer mipsTracer;
diff --git a/Core/MIPSTracer.cpp b/Core/MIPSTracer.cpp
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Core/MIPSTracer.h b/Core/MIPSTracer.h
deleted file mode 100644
index 6f70f09bee..0000000000
--- a/Core/MIPSTracer.h
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once