diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index f2daeb5cc..aef5f1f0d 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -282,6 +282,7 @@ set(pcsx2DebugToolsSources DebugTools/MIPSAnalyst.cpp DebugTools/MipsAssembler.cpp DebugTools/MipsAssemblerTables.cpp + DebugTools/MipsStackWalk.cpp DebugTools/Breakpoints.cpp DebugTools/SymbolMap.cpp DebugTools/DisR3000A.cpp @@ -298,6 +299,7 @@ set(pcsx2DebugToolsHeaders DebugTools/MIPSAnalyst.h DebugTools/MipsAssembler.h DebugTools/MipsAssemblerTables.h + DebugTools/MipsStackWalk.h DebugTools/Breakpoints.h DebugTools/SymbolMap.h DebugTools/Debug.h diff --git a/pcsx2/DebugTools/BiosDebugData.h b/pcsx2/DebugTools/BiosDebugData.h index e0daca58c..bbda49879 100644 --- a/pcsx2/DebugTools/BiosDebugData.h +++ b/pcsx2/DebugTools/BiosDebugData.h @@ -43,7 +43,7 @@ enum { struct EEThread { - u32 tid; + int tid; EEInternalThread data; }; diff --git a/pcsx2/DebugTools/MipsStackWalk.cpp b/pcsx2/DebugTools/MipsStackWalk.cpp new file mode 100644 index 000000000..2b9427b73 --- /dev/null +++ b/pcsx2/DebugTools/MipsStackWalk.cpp @@ -0,0 +1,190 @@ +#include "PrecompiledHeader.h" +#include "MipsStackWalk.h" +#include "SymbolMap.h" +#include "MIPSAnalyst.h" +#include "DebugInterface.h" +#include "../R5900OpcodeTables.h" + +#define _RS ((rawOp >> 21) & 0x1F) +#define _RT ((rawOp >> 16) & 0x1F) +#define _RD ((rawOp >> 11) & 0x1F) +#define _IMM16 ((signed short)(rawOp & 0xFFFF)) +#define MIPS_REG_SP 29 +#define MIPS_REG_FP 30 +#define MIPS_REG_RA 31 + +#define INVALIDTARGET 0xFFFFFFFF + +namespace MipsStackWalk { + // In the worst case, we scan this far above the pc for an entry. + const int MAX_FUNC_SIZE = 32768 * 4; + // After this we assume we're stuck. + const size_t MAX_DEPTH = 1024; + + static u32 GuessEntry(u32 pc) { + SymbolInfo info; + if (symbolMap.GetSymbolInfo(&info, pc)) { + return info.address; + } + return INVALIDTARGET; + } + + bool IsSWInstr(const R5900::OPCODE& op) { + if ((op.flags & IS_MEMORY) && (op.flags & IS_STORE)) + { + u32 type = op.flags & MEMTYPE_MASK; + switch (op.flags & MEMTYPE_MASK) + { + case MEMTYPE_WORD: + case MEMTYPE_DWORD: + case MEMTYPE_QWORD: + return true; + } + } + + return false; + } + + bool IsAddImmInstr(const R5900::OPCODE& op) { + if (op.flags & IS_ALU) + return (op.flags & ALUTYPE_MASK) == ALUTYPE_ADDI; + + return false; + } + + bool IsMovRegsInstr(const R5900::OPCODE& op, u32 rawOp) { + if (op.flags & IS_ALU) + return (op.flags & ALUTYPE_MASK) == ALUTYPE_ADDI && (_RS == 0 || _RT == 0); + + return false; + } + + bool ScanForAllocaSignature(DebugInterface* cpu, u32 pc) { + // In God Eater Burst, for example, after 0880E750, there's what looks like an alloca(). + // It's surrounded by "mov fp, sp" and "mov sp, fp", which is unlikely to be used for other reasons. + + // It ought to be pretty close. + u32 stop = pc - 32 * 4; + for (; cpu->isValidAddress(pc) && pc >= stop; pc -= 4) { + u32 rawOp = cpu->read32(pc); + const R5900::OPCODE& op = R5900::GetInstruction(rawOp); + + // We're looking for a "mov fp, sp" close by a "addiu sp, sp, -N". + if (IsMovRegsInstr(op,rawOp) && _RD == MIPS_REG_FP && (_RS == MIPS_REG_SP || _RT == MIPS_REG_SP)) { + return true; + } + } + return false; + } + + bool ScanForEntry(DebugInterface* cpu, StackFrame &frame, u32 entry, u32 &ra) { + // Let's hope there are no > 1MB functions on the PSP, for the sake of humanity... + const u32 LONGEST_FUNCTION = 1024 * 1024; + // TODO: Check if found entry is in the same symbol? Might be wrong sometimes... + + int ra_offset = -1; + const u32 start = frame.pc; + u32 stop = entry; + if (entry == INVALIDTARGET) { +/* if (start >= PSP_GetUserMemoryBase()) { + stop = PSP_GetUserMemoryBase(); + } else if (start >= PSP_GetKernelMemoryBase()) { + stop = PSP_GetKernelMemoryBase(); + } else if (start >= PSP_GetScratchpadMemoryBase()) { + stop = PSP_GetScratchpadMemoryBase(); + }*/ + stop = 0x80000; + } + if (stop < start - LONGEST_FUNCTION) { + stop = start - LONGEST_FUNCTION; + } + for (u32 pc = start; cpu->isValidAddress(pc) && pc >= stop; pc -= 4) { + u32 rawOp = cpu->read32(pc); + const R5900::OPCODE& op = R5900::GetInstruction(rawOp); + + // Here's where they store the ra address. + if (IsSWInstr(op) && _RT == MIPS_REG_RA && _RS == MIPS_REG_SP) { + ra_offset = _IMM16; + } + + if (IsAddImmInstr(op) && _RT == MIPS_REG_SP && _RS == MIPS_REG_SP) { + // A positive imm either means alloca() or we went too far. + if (_IMM16 > 0) { + // TODO: Maybe check for any alloca() signature and bail? + continue; + } + if (ScanForAllocaSignature(cpu,pc)) { + continue; + } + + frame.entry = pc; + frame.stackSize = -_IMM16; + if (ra_offset != -1 && cpu->isValidAddress(frame.sp + ra_offset)) { + ra = cpu->read32(frame.sp + ra_offset); + } + return true; + } + } + return false; + } + + bool DetermineFrameInfo(DebugInterface* cpu, StackFrame &frame, u32 possibleEntry, u32 threadEntry, u32 &ra) { + if (ScanForEntry(cpu, frame, possibleEntry, ra)) { + // Awesome, found one that looks right. + return true; + } else if (ra != INVALIDTARGET && possibleEntry != INVALIDTARGET) { + // Let's just assume it's a leaf. + frame.entry = possibleEntry; + frame.stackSize = 0; + return true; + } + + // Okay, we failed to get one. Our possibleEntry could be wrong, it often is. + // Let's just scan upward. + u32 newPossibleEntry = frame.pc > threadEntry ? threadEntry : frame.pc - MAX_FUNC_SIZE; + if (ScanForEntry(cpu, frame, newPossibleEntry, ra)) { + return true; + } else { + return false; + } + } + + std::vector Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry, u32 threadStackTop) { + std::vector frames; + StackFrame current; + current.pc = pc; + current.sp = sp; + current.entry = INVALIDTARGET; + current.stackSize = -1; + + u32 prevEntry = INVALIDTARGET; + while (pc != threadEntry) { + u32 possibleEntry = GuessEntry(current.pc); + if (DetermineFrameInfo(cpu, current, possibleEntry, threadEntry, ra)) { + frames.push_back(current); + if (current.entry == threadEntry || GuessEntry(current.entry) == threadEntry) { + break; + } + if (current.entry == prevEntry || frames.size() >= MAX_DEPTH) { + // Recursion, means we're screwed. Let's just give up. + break; + } + prevEntry = current.entry; + + current.pc = ra; + current.sp += current.stackSize; + ra = INVALIDTARGET; + current.entry = INVALIDTARGET; + current.stackSize = -1; + } else { + // Well, we got as far as we could. + current.entry = possibleEntry; + current.stackSize = 0; + frames.push_back(current); + break; + } + } + + return frames; + } +}; \ No newline at end of file diff --git a/pcsx2/DebugTools/MipsStackWalk.h b/pcsx2/DebugTools/MipsStackWalk.h new file mode 100644 index 000000000..285b2b0d8 --- /dev/null +++ b/pcsx2/DebugTools/MipsStackWalk.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "Pcsx2Types.h" + +class DebugInterface; + +namespace MipsStackWalk { + struct StackFrame { + // Beginning of function symbol (may be estimated.) + u32 entry; + // Next position within function. + u32 pc; + // Value of SP inside this function (assuming no alloca()...) + u32 sp; + // Size of stack frame in bytes. + int stackSize; + }; + + std::vector Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry, u32 threadStackTop); +}; \ No newline at end of file diff --git a/pcsx2/gui/Debugger/CtrlDisassemblyView.cpp b/pcsx2/gui/Debugger/CtrlDisassemblyView.cpp index 598af0ecd..b024dff53 100644 --- a/pcsx2/gui/Debugger/CtrlDisassemblyView.cpp +++ b/pcsx2/gui/Debugger/CtrlDisassemblyView.cpp @@ -889,11 +889,17 @@ void CtrlDisassemblyView::keydownEvent(wxKeyEvent& evt) } scanFunctions(); break; + case WXK_F8: + postEvent(debEVT_STEPOUT,0); + break; case WXK_F10: postEvent(debEVT_STEPOVER,0); return; case WXK_F11: - postEvent(debEVT_STEPINTO,0); + if (evt.ShiftDown()) + postEvent(debEVT_STEPOUT,0); + else + postEvent(debEVT_STEPINTO,0); return; default: evt.Skip(); diff --git a/pcsx2/gui/Debugger/DebugEvents.cpp b/pcsx2/gui/Debugger/DebugEvents.cpp index 8688f8f0f..eabb3c0e3 100644 --- a/pcsx2/gui/Debugger/DebugEvents.cpp +++ b/pcsx2/gui/Debugger/DebugEvents.cpp @@ -24,6 +24,7 @@ DEFINE_LOCAL_EVENT_TYPE( debEVT_RUNTOPOS ) DEFINE_LOCAL_EVENT_TYPE( debEVT_MAPLOADED ) DEFINE_LOCAL_EVENT_TYPE( debEVT_STEPOVER ) DEFINE_LOCAL_EVENT_TYPE( debEVT_STEPINTO ) +DEFINE_LOCAL_EVENT_TYPE( debEVT_STEPOUT ) DEFINE_LOCAL_EVENT_TYPE( debEVT_UPDATE ) DEFINE_LOCAL_EVENT_TYPE( debEVT_BREAKPOINTWINDOW ) diff --git a/pcsx2/gui/Debugger/DebugEvents.h b/pcsx2/gui/Debugger/DebugEvents.h index 15cd6ab58..876836c51 100644 --- a/pcsx2/gui/Debugger/DebugEvents.h +++ b/pcsx2/gui/Debugger/DebugEvents.h @@ -25,6 +25,7 @@ DECLARE_LOCAL_EVENT_TYPE( debEVT_RUNTOPOS, wxNewEventType() ) DECLARE_LOCAL_EVENT_TYPE( debEVT_MAPLOADED, wxNewEventType() ) DECLARE_LOCAL_EVENT_TYPE( debEVT_STEPOVER, wxNewEventType() ) DECLARE_LOCAL_EVENT_TYPE( debEVT_STEPINTO, wxNewEventType() ) +DECLARE_LOCAL_EVENT_TYPE( debEVT_STEPOUT, wxNewEventType() ) DECLARE_LOCAL_EVENT_TYPE( debEVT_UPDATE, wxNewEventType() ) DECLARE_LOCAL_EVENT_TYPE( debEVT_BREAKPOINTWINDOW, wxNewEventType() ) diff --git a/pcsx2/gui/Debugger/DebuggerLists.cpp b/pcsx2/gui/Debugger/DebuggerLists.cpp index 488e5f253..6528d7f8e 100644 --- a/pcsx2/gui/Debugger/DebuggerLists.cpp +++ b/pcsx2/gui/Debugger/DebuggerLists.cpp @@ -612,3 +612,108 @@ void ThreadList::onDoubleClick(int itemIndex, const wxPoint& point) break; } } + +EEThread ThreadList::getRunningThread() +{ + for (size_t i = 0; i < threads.size(); i++) + { + if (threads[i].data.status == THS_RUN) + return threads[i]; + } + + EEThread thread; + memset(&thread,0,sizeof(thread)); + thread.tid = -1; + return thread; +} + +// +// StackFramesList +// + +enum { SF_ENTRY, SF_ENTRYNAME, SF_CURPC, SF_CUROPCODE, SF_CURSP, SF_FRAMESIZE, SF_COLUMNCOUNT }; + +GenericListViewColumn stackFrameolumns[SF_COLUMNCOUNT] = { + { L"Entry", 0.12f }, + { L"Name", 0.24f }, + { L"PC", 0.12f }, + { L"Opcode", 0.28f }, + { L"SP", 0.12f }, + { L"Frame Size", 0.12f } +}; + +StackFramesList::StackFramesList(wxWindow* parent, DebugInterface* _cpu, CtrlDisassemblyView* _disassembly) + : GenericListView(parent,stackFrameolumns,SF_COLUMNCOUNT), cpu(_cpu), disassembly(_disassembly) +{ +#ifdef __linux__ + // On linux wx failed to resize properly the page. I don't know why so for the moment I just create a static size page + // Far from ideal but at least I can use the memory window! + this->SetSize(wxSize(1000, 200)); +#endif +} + +void StackFramesList::loadStackFrames(EEThread& currentThread) +{ + frames = MipsStackWalk::Walk(cpu,cpu->getPC(),cpu->getRegister(0,31),cpu->getRegister(0,29), + currentThread.data.entry_init,currentThread.data.stack); + update(); +} + +int StackFramesList::getRowCount() +{ + return frames.size(); +} + +wxString StackFramesList::getColumnText(int item, int col) const +{ + if (item < 0 || item >= (int)frames.size()) + return L""; + + FastFormatUnicode dest; + const MipsStackWalk::StackFrame& frame = frames[item]; + + switch (col) + { + case SF_ENTRY: + dest.Write("0x%08X",frame.entry); + break; + case SF_ENTRYNAME: + { + const std::string sym = symbolMap.GetLabelString(frame.entry); + if (!sym.empty()) { + dest.Write("%s",sym.c_str()); + } else { + dest.Write("-"); + } + } + break; + case SF_CURPC: + dest.Write("0x%08X",frame.pc); + break; + case SF_CUROPCODE: + { + char temp[512]; + disassembly->getOpcodeText(frame.pc,temp); + dest.Write("%s",temp); + } + break; + case SF_CURSP: + dest.Write("0x%08X",frame.sp); + break; + case SF_FRAMESIZE: + dest.Write("0x%08X",frame.stackSize); + break; + default: + return L"Invalid"; + } + + return dest; +} + +void StackFramesList::onDoubleClick(int itemIndex, const wxPoint& point) +{ + if (itemIndex < 0 || itemIndex >= (int)frames.size()) + return; + + postEvent(debEVT_GOTOINDISASM,frames[itemIndex].pc); +} diff --git a/pcsx2/gui/Debugger/DebuggerLists.h b/pcsx2/gui/Debugger/DebuggerLists.h index f48320df9..0036c2e60 100644 --- a/pcsx2/gui/Debugger/DebuggerLists.h +++ b/pcsx2/gui/Debugger/DebuggerLists.h @@ -18,6 +18,7 @@ #include "DebugTools/DebugInterface.h" #include "DebugTools/Breakpoints.h" #include "DebugTools/BiosDebugData.h" +#include "DebugTools/MipsStackWalk.h" #include "CtrlDisassemblyView.h" struct GenericListViewColumn @@ -88,6 +89,7 @@ class ThreadList: public GenericListView public: ThreadList(wxWindow* parent, DebugInterface* _cpu); void reloadThreads(); + EEThread getRunningThread(); protected: void onPopupClick(wxCommandEvent& evt); @@ -98,3 +100,20 @@ private: DebugInterface* cpu; std::vector threads; }; + +class StackFramesList: public GenericListView +{ +public: + StackFramesList(wxWindow* parent, DebugInterface* _cpu, CtrlDisassemblyView* _disassembly); + void loadStackFrames(EEThread& currentThread); +protected: + void onPopupClick(wxCommandEvent& evt); + + virtual wxString getColumnText(int row, int col) const; + virtual int getRowCount(); + virtual void onDoubleClick(int itemIndex, const wxPoint& point); +private: + DebugInterface* cpu; + CtrlDisassemblyView* disassembly; + std::vector frames; +}; diff --git a/pcsx2/gui/Debugger/DisassemblyDialog.cpp b/pcsx2/gui/Debugger/DisassemblyDialog.cpp index f5ec5ddc8..1f642918e 100644 --- a/pcsx2/gui/Debugger/DisassemblyDialog.cpp +++ b/pcsx2/gui/Debugger/DisassemblyDialog.cpp @@ -19,6 +19,7 @@ #include "DebugTools/DebugInterface.h" #include "DebugTools/DisassemblyManager.h" #include "DebugTools/Breakpoints.h" +#include "DebugTools/MipsStackWalk.h" #include "BreakpointWindow.h" #include "PathDefs.h" @@ -34,6 +35,7 @@ BEGIN_EVENT_TABLE(DisassemblyDialog, wxFrame) EVT_COMMAND( wxID_ANY, debEVT_GOTOINDISASM, DisassemblyDialog::onDebuggerEvent ) EVT_COMMAND( wxID_ANY, debEVT_STEPOVER, DisassemblyDialog::onDebuggerEvent ) EVT_COMMAND( wxID_ANY, debEVT_STEPINTO, DisassemblyDialog::onDebuggerEvent ) + EVT_COMMAND( wxID_ANY, debEVT_STEPOUT, DisassemblyDialog::onDebuggerEvent ) EVT_COMMAND( wxID_ANY, debEVT_UPDATE, DisassemblyDialog::onDebuggerEvent ) EVT_COMMAND( wxID_ANY, debEVT_BREAKPOINTWINDOW, DisassemblyDialog::onDebuggerEvent ) EVT_COMMAND( wxID_ANY, debEVT_MAPLOADED, DisassemblyDialog::onDebuggerEvent ) @@ -109,10 +111,14 @@ CpuTabPage::CpuTabPage(wxWindow* parent, DebugInterface* _cpu) bottomTabs->AddPage(breakpointList,L"Breakpoints"); threadList = NULL; + stackFrames = NULL; if (cpu == &r5900Debug) { threadList = new ThreadList(bottomTabs,cpu); bottomTabs->AddPage(threadList,L"Threads"); + + stackFrames = new StackFramesList(bottomTabs,cpu,disassembly); + bottomTabs->AddPage(stackFrames,L"Stack frames"); } mainSizer->Add(bottomTabs,1,wxEXPAND); @@ -171,8 +177,13 @@ void CpuTabPage::update() breakpointList->reloadBreakpoints(); if (threadList != NULL) + { threadList->reloadThreads(); + EEThread thread = threadList->getRunningThread(); + if (thread.tid != -1) + stackFrames->loadStackFrames(thread); + } Refresh(); } @@ -186,6 +197,22 @@ void CpuTabPage::loadCycles() lastCycles = cycles; } +u32 CpuTabPage::getStepOutAddress() +{ + if (threadList == NULL) + return (u32)-1; + + EEThread currentThread = threadList->getRunningThread(); + std::vector frames = + MipsStackWalk::Walk(cpu,cpu->getPC(),cpu->getRegister(0,31),cpu->getRegister(0,29), + currentThread.data.entry_init,currentThread.data.stack); + + if (frames.size() < 2) + return (u32)-1; + + return frames[1].pc; +} + DisassemblyDialog::DisassemblyDialog(wxWindow* parent): wxFrame( parent, wxID_ANY, L"Debugger", wxDefaultPosition,wxDefaultSize,wxRESIZE_BORDER|wxCLOSE_BOX|wxCAPTION|wxSYSTEM_MENU ), currentCpu(NULL) @@ -215,6 +242,7 @@ DisassemblyDialog::DisassemblyDialog(wxWindow* parent): stepOutButton = new wxButton( panel, wxID_ANY, L"Step Out" ); stepOutButton->Enable(false); + Connect( stepOutButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DisassemblyDialog::onStepOutClicked ) ); topRowSizer->Add(stepOutButton,0,wxRIGHT,8); breakpointButton = new wxButton( panel, wxID_ANY, L"Breakpoint" ); @@ -297,6 +325,11 @@ void DisassemblyDialog::onStepIntoClicked(wxCommandEvent& evt) stepInto(); } +void DisassemblyDialog::onStepOutClicked(wxCommandEvent& evt) +{ + stepOut(); +} + void DisassemblyDialog::onPageChanging(wxCommandEvent& evt) { wxNotebook* notebook = (wxNotebook*)wxWindow::FindWindowById(evt.GetId()); @@ -404,6 +437,18 @@ void DisassemblyDialog::stepInto() r5900Debug.resumeCpu(); } +void DisassemblyDialog::stepOut() +{ + if (!r5900Debug.isAlive() || !r5900Debug.isCpuPaused() || currentCpu == NULL) + return; + + u32 addr = currentCpu->getStepOutAddress(); + if (addr == (u32)-1) + return; + + CBreakPoints::AddBreakPoint(addr,true); + r5900Debug.resumeCpu(); +} void DisassemblyDialog::onBreakpointClick(wxCommandEvent& evt) { @@ -475,6 +520,10 @@ void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt) { eeTab->reloadSymbolMap(); iopTab->reloadSymbolMap(); + } else if (type == debEVT_STEPOUT) + { + if (currentCpu != NULL) + stepOut(); } } @@ -526,6 +575,7 @@ void DisassemblyDialog::setDebugMode(bool debugMode, bool switchPC) stepOverButton->Enable(true); stepIntoButton->Enable(true); + stepOutButton->Enable(currentCpu == eeTab); if (switchPC || CBreakPoints::GetBreakpointTriggered()) gotoPc(); diff --git a/pcsx2/gui/Debugger/DisassemblyDialog.h b/pcsx2/gui/Debugger/DisassemblyDialog.h index 4484daa20..ab2d0cb62 100644 --- a/pcsx2/gui/Debugger/DisassemblyDialog.h +++ b/pcsx2/gui/Debugger/DisassemblyDialog.h @@ -43,6 +43,7 @@ public: void showMemoryView() { setBottomTabPage(memory); }; void loadCycles(); void reloadSymbolMap(); + u32 getStepOutAddress(); void listBoxHandler(wxCommandEvent& event); DECLARE_EVENT_TABLE() @@ -60,6 +61,7 @@ private: BreakpointList* breakpointList; wxStaticText* cyclesText; ThreadList* threadList; + StackFramesList* stackFrames; u32 lastCycles; }; @@ -85,12 +87,14 @@ protected: void onBreakRunClicked(wxCommandEvent& evt); void onStepOverClicked(wxCommandEvent& evt); void onStepIntoClicked(wxCommandEvent& evt); + void onStepOutClicked(wxCommandEvent& evt); void onDebuggerEvent(wxCommandEvent& evt); void onPageChanging(wxCommandEvent& evt); void onBreakpointClick(wxCommandEvent& evt); void onClose(wxCloseEvent& evt); void stepOver(); void stepInto(); + void stepOut(); void gotoPc(); private: CpuTabPage* eeTab; diff --git a/pcsx2/windows/VCprojects/pcsx2.vcxproj b/pcsx2/windows/VCprojects/pcsx2.vcxproj index 18f682358..deb70be02 100644 --- a/pcsx2/windows/VCprojects/pcsx2.vcxproj +++ b/pcsx2/windows/VCprojects/pcsx2.vcxproj @@ -179,6 +179,7 @@ %(RootDir)%(Directory)\%(Filename).h + @@ -718,6 +719,7 @@ + @@ -935,4 +937,4 @@ - + \ No newline at end of file diff --git a/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters b/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters index 8ebc4642a..58eb17b43 100644 --- a/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters +++ b/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters @@ -856,6 +856,9 @@ System\ISO + + System\Ps2\Debug + @@ -1269,6 +1272,9 @@ System\ISO + + System\Ps2\Debug + @@ -1351,4 +1357,4 @@ AppHost\Resources - + \ No newline at end of file diff --git a/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj b/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj index 26b283f10..648b4ceb7 100644 --- a/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj +++ b/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj @@ -416,6 +416,7 @@ + @@ -704,6 +705,7 @@ + @@ -940,4 +942,4 @@ - + \ No newline at end of file diff --git a/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj.filters b/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj.filters index 1153d41a4..3bb1e3586 100644 --- a/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj.filters +++ b/pcsx2/windows/VCprojects/pcsx2_vs2012.vcxproj.filters @@ -853,6 +853,9 @@ System\ISO + + System\Ps2\Debug + @@ -1269,6 +1272,9 @@ System\ISO + + System\Ps2\Debug + @@ -1351,4 +1357,4 @@ AppHost\Resources - + \ No newline at end of file diff --git a/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj b/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj index 5f345811a..98dea47e9 100644 --- a/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj +++ b/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj @@ -416,6 +416,7 @@ + @@ -704,6 +705,7 @@ + diff --git a/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj.filters b/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj.filters index ec441c1b3..62717f06c 100644 --- a/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj.filters +++ b/pcsx2/windows/VCprojects/pcsx2_vs2013.vcxproj.filters @@ -853,6 +853,9 @@ System\Ps2\Debug + + System\Ps2\Debug + @@ -1269,6 +1272,9 @@ System\Ps2\Debug + + System\Ps2\Debug +