void EmuScreen::sendMessage(const char *message, const char *value) { // External commands, like from the Windows UI. if (!strcmp(message, "pause")) { screenManager()->push(new PauseScreen()); } else if (!strcmp(message, "stop")) { if (g_Config.bNewUI) screenManager()->switchScreen(new MainScreen()); else screenManager()->switchScreen(new MenuScreen()); } else if (!strcmp(message, "reset")) { PSP_Shutdown(); std::string resetError; if (!PSP_Init(PSP_CoreParameter(), &resetError)) { ELOG("Error resetting: %s", resetError.c_str()); if (g_Config.bNewUI) screenManager()->switchScreen(new MainScreen()); else screenManager()->switchScreen(new MenuScreen()); return; } host->BootDone(); host->UpdateDisassembly(); #ifdef _WIN32 if (g_Config.bAutoRun) { Core_EnableStepping(false); } else { Core_EnableStepping(true); } #endif } }
void CBreakPoints::Update(u32 addr) { if (MIPSComp::jit) { bool resume = false; if (Core_IsStepping() == false) { Core_EnableStepping(true); Core_WaitInactive(200); resume = true; } // In case this is a delay slot, clear the previous instruction too. if (addr != 0) MIPSComp::jit->InvalidateCacheAt(addr - 4, 8); else MIPSComp::jit->InvalidateCache(); if (resume) Core_EnableStepping(false); } // Redraw in order to show the breakpoint. host->UpdateDisassembly(); }
EmuScreen::EmuScreen(const std::string &filename) : invalid_(true) { CheckGLExtensions(); std::string fileToStart = filename; // This is probably where we should start up the emulated PSP. INFO_LOG(BOOT, "Starting up hardware."); CoreParameter coreParam; coreParam.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER; coreParam.gpuCore = GPU_GLES; coreParam.enableSound = g_Config.bEnableSound; coreParam.fileToStart = fileToStart; coreParam.mountIso = ""; coreParam.startPaused = false; coreParam.enableDebugging = false; coreParam.printfEmuLog = false; coreParam.headLess = false; #ifndef _WIN32 if (g_Config.iWindowZoom < 1 || g_Config.iWindowZoom > 2) g_Config.iWindowZoom = 1; #endif coreParam.renderWidth = 480 * g_Config.iWindowZoom; coreParam.renderHeight = 272 * g_Config.iWindowZoom; coreParam.outputWidth = dp_xres; coreParam.outputHeight = dp_yres; coreParam.pixelWidth = pixel_xres; coreParam.pixelHeight = pixel_yres; coreParam.useMediaEngine = false; std::string error_string; if (PSP_Init(coreParam, &error_string)) { invalid_ = false; } else { invalid_ = true; errorMessage_ = error_string; ERROR_LOG(BOOT, "%s", errorMessage_.c_str()); return; } globalUIState = UISTATE_INGAME; host->BootDone(); host->UpdateDisassembly(); #ifdef _WIN32 if (g_Config.bAutoRun) { Core_EnableStepping(false); } else { Core_EnableStepping(true); } #endif LayoutGamepad(dp_xres, dp_yres); NOTICE_LOG(BOOT, "Loading %s...", fileToStart.c_str()); }
void BrowseAndBoot(std::string defaultPath, bool browseDirectory) { std::string fn; std::string filter = "PSP ROMs (*.iso *.cso *.pbp *.elf)|*.pbp;*.elf;*.iso;*.cso;*.prx|All files (*.*)|*.*||"; for (int i=0; i<(int)filter.length(); i++) { if (filter[i] == '|') filter[i] = '\0'; } // Pause if a game is being played. bool isPaused = false; if (globalUIState == UISTATE_INGAME) { isPaused = Core_IsStepping(); if (!isPaused) Core_EnableStepping(true); } if (browseDirectory) { std::string dir = W32Util::BrowseForFolder(GetHWND(),"Choose directory"); if (dir == "") { if (!isPaused) Core_EnableStepping(false); } else { if (globalUIState == UISTATE_INGAME || globalUIState == UISTATE_PAUSEMENU) { Core_EnableStepping(false); } NativeMessageReceived("boot", dir.c_str()); } } else if (W32Util::BrowseForFileName(true, GetHWND(), "Load File", defaultPath.size() ? defaultPath.c_str() : 0, filter.c_str(),"*.pbp;*.elf;*.iso;*.cso;",fn)) { if (globalUIState == UISTATE_INGAME || globalUIState == UISTATE_PAUSEMENU) { Core_EnableStepping(false); } // Decode the filename with fullpath. std::string fullpath = fn; char drive[MAX_PATH]; char dir[MAX_PATH]; char fname[MAX_PATH]; char ext[MAX_PATH]; _splitpath(fullpath.c_str(), drive, dir, fname, ext); std::string executable = std::string(drive) + std::string(dir) + std::string(fname) + std::string(ext); NativeMessageReceived("boot", executable.c_str()); } else { if (!isPaused) Core_EnableStepping(false); } }
void EmuScreen::sendMessage(const char *message, const char *value) { // External commands, like from the Windows UI. if (!strcmp(message, "pause")) { screenManager()->push(new GamePauseScreen(gamePath_)); } else if (!strcmp(message, "stop")) { // We will push MainScreen in update(). PSP_Shutdown(); booted_ = false; invalid_ = true; } else if (!strcmp(message, "reset")) { PSP_Shutdown(); booted_ = false; invalid_ = true; std::string resetError; if (!PSP_InitStart(PSP_CoreParameter(), &resetError)) { ELOG("Error resetting: %s", resetError.c_str()); screenManager()->switchScreen(new MainScreen()); System_SendMessage("event", "failstartgame"); return; } #ifndef MOBILE_DEVICE if (g_Config.bAutoRun) { Core_EnableStepping(false); } else { Core_EnableStepping(true); } #endif } else if (!strcmp(message, "boot")) { PSP_Shutdown(); booted_ = false; bootGame(value); } else if (!strcmp(message, "control mapping")) { UpdateUIState(UISTATE_MENU); screenManager()->push(new ControlMappingScreen()); } else if (!strcmp(message, "settings")) { UpdateUIState(UISTATE_MENU); screenManager()->push(new GameSettingsScreen(gamePath_)); } else if (!strcmp(message, "gpu resized") || !strcmp(message, "gpu clear cache")) { if (gpu) { gpu->ClearCacheNextFrame(); gpu->Resized(); } Reporting::UpdateConfig(); RecreateViews(); } else if (!strcmp(message, "gpu dump next frame")) { if (gpu) gpu->DumpNextFrame(); } else if (!strcmp(message, "clear jit")) { if (MIPSComp::jit) { MIPSComp::jit->ClearCache(); } } }
inline void ReadFromHardware(T &var, const u32 address) { // TODO: Figure out the fastest order of tests for both read and write (they are probably different). // TODO: Make sure this represents the mirrors in a correct way. // Could just do a base-relative read, too.... TODO if ((address & 0x0E000000) == 0x08000000) { var = *((const T*)&m_pRAM[address & RAM_MASK]); } else if ((address & 0x0F800000) == 0x04000000) { var = *((const T*)&m_pVRAM[address & VRAM_MASK]); } else if ((address & 0xBFFF0000) == 0x00010000) { // Scratchpad var = *((const T*)&m_pScratchPad[address & SCRATCHPAD_MASK]); } else { WARN_LOG(MEMMAP, "ReadFromHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); if (!g_Config.bIgnoreBadMemAccess) { Core_EnableStepping(true); host->SetDebugMode(true); } var = 0; } }
void WindowsHost::BootDone() { g_symbolMap->SortSymbols(); SendMessage(mainWindow_, WM_USER + 1, 0, 0); SetDebugMode(!g_Config.bAutoRun); Core_EnableStepping(!g_Config.bAutoRun); }
u8 *GetPointer(const u32 address) { if ((address & 0x3E000000) == 0x08000000) { return m_pRAM + (address & RAM_NORMAL_MASK); } else if ((address & 0x3F800000) == 0x04000000) { return m_pVRAM + (address & VRAM_MASK); } else if ((address & 0xBFFF0000) == 0x00010000) { return m_pScratchPad + (address & SCRATCHPAD_MASK); } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { return m_pRAM + (address & g_MemoryMask); } else { ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); static bool reported = false; if (!reported) { Reporting::ReportMessage("Unknown GetPointer %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); reported = true; } if (!g_Config.bIgnoreBadMemAccess) { Core_EnableStepping(true); host->SetDebugMode(true); } return 0; } }
void JitBreakpoint() { Core_EnableStepping(true); host->SetDebugMode(true); if (CBreakPoints::IsTempBreakPoint(currentMIPS->pc)) CBreakPoints::RemoveBreakPoint(currentMIPS->pc); // There's probably a better place for this. if (USE_JIT_MISSMAP) { std::map<u32, std::string> notJitSorted; std::transform(notJitOps.begin(), notJitOps.end(), std::inserter(notJitSorted, notJitSorted.begin()), flip_pair<std::string, u32>); std::string message; char temp[256]; int remaining = 15; for (auto it = notJitSorted.rbegin(), end = notJitSorted.rend(); it != end && --remaining >= 0; ++it) { snprintf(temp, 256, " (%d), ", it->first); message += it->second + temp; } if (message.size() > 2) message.resize(message.size() - 2); NOTICE_LOG(JIT, "Top ops compiled to interpreter: %s", message.c_str()); } }
BreakAction CBreakPoints::ExecBreakPoint(u32 addr) { size_t bp = FindBreakpoint(addr, false); if (bp != INVALID_BREAKPOINT) { if (breakPoints_[bp].hasCond) { // Evaluate the breakpoint and abort if necessary. auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); if (cond && !cond->Evaluate()) return BREAK_ACTION_IGNORE; } if (breakPoints_[bp].result & BREAK_ACTION_LOG) { if (breakPoints_[bp].logFormat.empty()) { NOTICE_LOG(JIT, "BKP PC=%08x (%s)", addr, g_symbolMap->GetDescription(addr).c_str()); } else { std::string formatted; CBreakPoints::EvaluateLogFormat(currentDebugMIPS, breakPoints_[bp].logFormat, formatted); NOTICE_LOG(JIT, "BKP PC=%08x: %s", addr, formatted.c_str()); } } if (breakPoints_[bp].result & BREAK_ACTION_PAUSE) { Core_EnableStepping(true); host->SetDebugMode(true); } return breakPoints_[bp].result; } return BREAK_ACTION_IGNORE; }
void CDisasm::stepOut() { auto threads = GetThreadsInfo(); u32 entry, stackTop; for (size_t i = 0; i < threads.size(); i++) { if (threads[i].isCurrent) { entry = threads[i].entrypoint; stackTop = threads[i].initialStack; break; } } auto frames = MIPSStackWalk::Walk(cpu->GetPC(),cpu->GetRegValue(0,31),cpu->GetRegValue(0,29),entry,stackTop); if (frames.size() < 2) return; u32 breakpointAddress = frames[1].pc; // If the current PC is on a breakpoint, the user doesn't want to do nothing. CBreakPoints::SetSkipFirst(currentMIPS->pc); CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg,IDC_DISASMVIEW)); ptr->setDontRedraw(true); SetDebugMode(false); CBreakPoints::AddBreakPoint(breakpointAddress,true); _dbg_update_(); Core_EnableStepping(false); Sleep(1); ptr->gotoAddr(breakpointAddress); UpdateDialog(); }
inline void WriteToHardware(u32 address, const T data) { // Could just do a base-relative write, too.... TODO if ((address & 0x0E000000) == 0x08000000) { *(T*)&m_pRAM[address & RAM_MASK] = data; } else if ((address & 0x0F800000) == 0x04000000) { *(T*)&m_pVRAM[address & VRAM_MASK] = data; } else if ((address & 0xBFFF0000) == 0x00010000) { *(T*)&m_pScratchPad[address & SCRATCHPAD_MASK] = data; } else { WARN_LOG(MEMMAP, "WriteToHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); if (!g_Config.bIgnoreBadMemAccess) { Core_EnableStepping(true); host->SetDebugMode(true); } } }
inline void WriteToHardware(u32 address, const T data) { // Could just do a base-relative write, too.... TODO if ((address & 0x3E000000) == 0x08000000) { *(T*)&m_pRAM[address & RAM_NORMAL_MASK] = data; } else if ((address & 0x3F800000) == 0x04000000) { *(T*)&m_pVRAM[address & VRAM_MASK] = data; } else if ((address & 0xBFFF0000) == 0x00010000) { *(T*)&m_pScratchPad[address & SCRATCHPAD_MASK] = data; } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { *(T*)&m_pRAM[address & g_MemoryMask] = data; } else { if (g_Config.bJit) { WARN_LOG(MEMMAP, "WriteToHardware: Invalid address %08x", address); } else { WARN_LOG(MEMMAP, "WriteToHardware: Invalid address %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); } static bool reported = false; if (!reported) { Reporting::ReportMessage("WriteToHardware: Invalid address %08x near PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); reported = true; } if (!g_Config.bIgnoreBadMemAccess) { Core_EnableStepping(true); host->SetDebugMode(true); } } }
void EmuScreen::sendMessage(const char *message, const char *value) { // External commands, like from the Windows UI. if (!strcmp(message, "pause")) { screenManager()->push(new GamePauseScreen(gamePath_)); } else if (!strcmp(message, "stop")) { // We will push MainScreen in update(). PSP_Shutdown(); } else if (!strcmp(message, "reset")) { PSP_Shutdown(); std::string resetError; if (!PSP_Init(PSP_CoreParameter(), &resetError)) { ELOG("Error resetting: %s", resetError.c_str()); screenManager()->switchScreen(new MainScreen()); return; } host->BootDone(); host->UpdateDisassembly(); #ifdef _WIN32 if (g_Config.bAutoRun) { Core_EnableStepping(false); } else { Core_EnableStepping(true); } #endif } else if (!strcmp(message, "boot")) { PSP_Shutdown(); bootGame(value); } else if (!strcmp(message, "control mapping")) { UpdateUIState(UISTATE_MENU); screenManager()->push(new ControlMappingScreen()); } else if (!strcmp(message, "settings")) { UpdateUIState(UISTATE_MENU); screenManager()->push(new GameSettingsScreen(gamePath_)); } else if (!strcmp(message, "gpu resized")) { if (gpu) gpu->Resized(); } else if (!strcmp(message, "gpu clear cache")) { if (gpu) gpu->ClearCacheNextFrame(); } else if (!strcmp(message, "gpu dump next frame")) { if (gpu) gpu->DumpNextFrame(); } }
void WindowsHost::BootDone() { symbolMap.SortSymbols(); SendMessage(MainWindow::GetHWND(), WM_USER+1, 0,0); SetDebugMode(!g_Config.bAutoRun); Core_EnableStepping(!g_Config.bAutoRun); }
void MemCheck::JitBeforeAction(u32 addr, bool write, int size, u32 pc) { if (lastAddr) { // We have to break to find out if it changed. Core_EnableStepping(true); } else { Action(addr, write, size, pc); } }
void Debugger_Disasm::Go() { SetDebugMode(false); EmuThread_LockDraw(true); Core_EnableStepping(false); EmuThread_LockDraw(false); mainWindow->UpdateMenus(); }
void Debugger_Disasm::Stop() { SetDebugMode(true); Core_EnableStepping(true); _dbg_update_(); mainWindow->updateMenus(); UpdateDialog(); }
void Debugger_Disasm::StepOver() { SetDebugMode(false); CBreakPoints::AddBreakPoint(cpu->GetPC()+cpu->getInstructionSize(0),true); _dbg_update_(); Core_EnableStepping(false); mainWindow->updateMenus(); }
void Debugger_Disasm::StepHLE() { hleDebugBreak(); SetDebugMode(false); _dbg_update_(); Core_EnableStepping(false); mainWindow->updateMenus(); }
void CDisasm::stepOver() { if (Core_IsActive()) return; CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg,IDC_DISASMVIEW)); lastTicks = CoreTiming::GetTicks(); // If the current PC is on a breakpoint, the user doesn't want to do nothing. CBreakPoints::SetSkipFirst(currentMIPS->pc); u32 currentPc = cpu->GetPC(); u32 windowEnd = ptr->getWindowEnd(); MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu,cpu->GetPC()); ptr->setDontRedraw(true); u32 breakpointAddress = currentPc+cpu->getInstructionSize(0); if (info.isBranch) { if (info.isConditional == false) { if (info.isLinkedBranch) // jal, jalr { // it's a function call with a delay slot - skip that too breakpointAddress += cpu->getInstructionSize(0); } else { // j, ... // in case of absolute branches, set the breakpoint at the branch target breakpointAddress = info.branchTarget; } } else { // beq, ... if (info.conditionMet) { breakpointAddress = info.branchTarget; } else { breakpointAddress = currentPc+2*cpu->getInstructionSize(0); if (breakpointAddress == windowEnd-4) ptr->scrollWindow(1); else if (breakpointAddress == windowEnd) ptr->scrollWindow(2); else if (breakpointAddress == windowEnd+4) ptr->scrollWindow(3); } } } else { if (breakpointAddress == windowEnd-4) ptr->scrollWindow(1); else if (breakpointAddress == windowEnd) ptr->scrollWindow(2); } SetDebugMode(false, true); CBreakPoints::AddBreakPoint(breakpointAddress,true); _dbg_update_(); Core_EnableStepping(false); Sleep(1); ptr->gotoAddr(breakpointAddress); UpdateDialog(); }
void Debugger_Disasm::StepHLE() { EmuThread_LockDraw(true); hleDebugBreak(); SetDebugMode(false); _dbg_update_(); Core_EnableStepping(false); EmuThread_LockDraw(false); mainWindow->UpdateMenus(); }
void Debugger_Disasm::Stop() { SetDebugMode(true); EmuThread_LockDraw(true); Core_EnableStepping(true); EmuThread_LockDraw(false); _dbg_update_(); mainWindow->UpdateMenus(); UpdateDialog(); }
void CtrlMemView::onChar(WPARAM wParam, LPARAM lParam) { auto memLock = Memory::Lock(); if (!PSP_IsInited()) return; if (KeyDownAsync(VK_CONTROL) || wParam == VK_TAB) return; if (!Memory::IsValidAddress(curAddress)) { scrollCursor(1); return; } bool active = Core_IsActive(); if (active) Core_EnableStepping(true); if (asciiSelected) { u8 newValue = wParam; Memory::WriteUnchecked_U8(newValue,curAddress); scrollCursor(1); } else { wParam = tolower(wParam); int inputValue = -1; if (wParam >= '0' && wParam <= '9') inputValue = wParam - '0'; if (wParam >= 'a' && wParam <= 'f') inputValue = wParam -'a' + 10; if (inputValue >= 0) { int shiftAmount = (1-selectedNibble)*4; u8 oldValue = Memory::ReadUnchecked_U8(curAddress); oldValue &= ~(0xF << shiftAmount); u8 newValue = oldValue | (inputValue << shiftAmount); Memory::WriteUnchecked_U8(newValue,curAddress); scrollCursor(1); } } if (active) Core_EnableStepping(false); }
void CDisasm::runToLine() { CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg,IDC_DISASMVIEW)); u32 pos = ptr->getSelection(); lastTicks = CoreTiming::GetTicks(); ptr->setDontRedraw(true); SetDebugMode(false); CBreakPoints::AddBreakPoint(pos,true); _dbg_update_(); Core_EnableStepping(false); }
BreakAction MemCheck::Action(u32 addr, bool write, int size, u32 pc) { int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ; if (cond & mask) { Log(addr, write, size, pc); if (result & BREAK_ACTION_PAUSE) { Core_EnableStepping(true); host->SetDebugMode(true); } return result; } return BREAK_ACTION_IGNORE; }
void MemCheck::Action(u32 addr, bool write, int size, u32 pc) { int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ; if (cond & mask) { ++numHits; Log(addr, write, size, pc); if (result & MEMCHECK_BREAK) { Core_EnableStepping(true); host->SetDebugMode(true); } } }
void MemCheck::Action(u32 addr, bool write, int size, u32 pc) { if ((write && bOnWrite) || (!write && bOnRead)) { ++numHits; if (bLog) NOTICE_LOG(MEMMAP, "CHK %s%i at %08x (%s), PC=%08x (%s)", write ? "Write" : "Read", size * 8, addr, symbolMap.GetDescription(addr), pc, symbolMap.GetDescription(pc)); if (bBreak) { Core_EnableStepping(true); host->SetDebugMode(true); } } }
void MemCheck::Action(u32 addr, bool write, int size, u32 pc) { int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ; if (cond & mask) { ++numHits; if (result & MEMCHECK_LOG) NOTICE_LOG(MEMMAP, "CHK %s%i at %08x (%s), PC=%08x (%s)", write ? "Write" : "Read", size * 8, addr, symbolMap.GetDescription(addr), pc, symbolMap.GetDescription(pc)); if (result & MEMCHECK_BREAK) { Core_EnableStepping(true); host->SetDebugMode(true); } } }
// Pauses execution after an HLE call. bool hleExecuteDebugBreak(const HLEFunction &func) { const u32 NID_SUSPEND_INTR = 0x092968F4, NID_RESUME_INTR = 0x5F10D406; // Never break on these, they're noise. u32 blacklistedNIDs[] = {NID_SUSPEND_INTR, NID_RESUME_INTR, NID_IDLE}; for (size_t i = 0; i < ARRAY_SIZE(blacklistedNIDs); ++i) { if (func.ID == blacklistedNIDs[i]) return false; } Core_EnableStepping(true); host->SetDebugMode(true); return true; }