/**************************************************************************** * * * Project64 - A Nintendo 64 emulator. * * http://www.pj64-emu.com/ * * Copyright (C) 2012 Project64. All rights reserved. * * * * License: * * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ #include "stdafx.h" #include "Breakpoints.h" #include #include #include #include CBreakpoints::CBreakpoints() : m_GPRWriteBP(0), m_GPRReadBP(0), m_HIWriteBP(false), m_HIReadBP(false), m_LOWriteBP(false), m_LOReadBP(false) { } bool CBreakpoints::RBPAdd(uint32_t address) { if (!ReadBPExists8(address)) { PreUpdateBP(); m_ReadMem.insert(breakpoints_t::value_type(address, false)); UpdateAlignedReadBP(); if (!HaveReadBP()) { g_Settings->SaveBool(Debugger_ReadBPExists, true); } PostUpdateBP(); return true; } return false; } bool CBreakpoints::WBPAdd(uint32_t address) { if (!WriteBPExists8(address)) { PreUpdateBP(); m_WriteMem.insert(breakpoints_t::value_type(address, false)); UpdateAlignedWriteBP(); if (!HaveWriteBP()) { g_Settings->SaveBool(Debugger_WriteBPExists, true); } PostUpdateBP(); return true; } return false; } bool CBreakpoints::AddExecution(uint32_t address, bool bTemporary) { PreUpdateBP(); breakpoints_t::_Pairib res = m_Execution.insert(breakpoint_t::value_type(address, bTemporary)); if (!res.second && !bTemporary) { res.first->second = true; } if (!HaveExecutionBP()) { g_Settings->SaveBool(Debugger_HaveExecutionBP, true); } PostUpdateBP(); return !res.second; } void CBreakpoints::RBPRemove(uint32_t address) { PreUpdateBP(); breakpoints_t::iterator itr = m_ReadMem.find(address); if (itr != m_ReadMem.end()) { m_ReadMem.erase(itr); UpdateAlignedWriteBP(); if (m_ReadMem.size() == 0) { g_Settings->SaveBool(Debugger_ReadBPExists, false); } } PostUpdateBP(); } void CBreakpoints::WBPRemove(uint32_t address) { PreUpdateBP(); breakpoints_t::iterator itr = m_WriteMem.find(address); if (itr != m_WriteMem.end()) { m_WriteMem.erase(itr); UpdateAlignedWriteBP(); if (m_WriteMem.size() == 0) { g_Settings->SaveBool(Debugger_WriteBPExists, false); } } PostUpdateBP(); } void CBreakpoints::RemoveExecution(uint32_t address) { PreUpdateBP(); breakpoints_t::iterator itr = m_Execution.find(address); if (itr != m_Execution.end()) { m_Execution.erase(itr); if (m_Execution.size() == 0) { g_Settings->SaveBool(Debugger_HaveExecutionBP, false); } } PostUpdateBP(); } void CBreakpoints::RBPToggle(uint32_t address) { if (RBPAdd(address) == false) { RBPRemove(address); } } void CBreakpoints::WBPToggle(uint32_t address) { if (WBPAdd(address) == false) { WBPRemove(address); } } void CBreakpoints::EBPToggle(uint32_t address, bool bTemporary) { if (AddExecution(address, bTemporary) == false) { RemoveExecution(address); } } void CBreakpoints::RBPClear() { PreUpdateBP(); m_ReadMem.clear(); UpdateAlignedReadBP(); g_Settings->SaveBool(Debugger_ReadBPExists, false); PostUpdateBP(); } void CBreakpoints::WBPClear() { PreUpdateBP(); m_WriteMem.clear(); UpdateAlignedWriteBP(); g_Settings->SaveBool(Debugger_WriteBPExists, false); PostUpdateBP(); } void CBreakpoints::EBPClear() { PreUpdateBP(); m_Execution.clear(); g_Settings->SaveBool(Debugger_HaveExecutionBP, false); PostUpdateBP(); } void CBreakpoints::BPClear() { RBPClear(); WBPClear(); EBPClear(); } CBreakpoints::BPSTATE CBreakpoints::ReadBPExists8(uint32_t address) { breakpoints_t::const_iterator itr = m_ReadMem.find(address); if (itr != m_ReadMem.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::ReadBPExists16(uint32_t address) { breakpoints_t::const_iterator itr = m_ReadMem16.find(address); if (itr != m_ReadMem16.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::ReadBPExists32(uint32_t address) { breakpoints_t::const_iterator itr = m_ReadMem32.find(address); if (itr != m_ReadMem32.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::ReadBPExists64(uint32_t address) { breakpoints_t::const_iterator itr = m_ReadMem64.find(address); if (itr != m_ReadMem64.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::WriteBPExists8(uint32_t address) { breakpoints_t::const_iterator itr = m_WriteMem.find(address); if (itr != m_WriteMem.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::WriteBPExists16(uint32_t address) { breakpoints_t::const_iterator itr = m_WriteMem16.find(address); if (itr != m_WriteMem16.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::WriteBPExists32(uint32_t address) { breakpoints_t::const_iterator itr = m_WriteMem32.find(address); if (itr != m_WriteMem32.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::WriteBPExists64(uint32_t address) { breakpoints_t::const_iterator itr = m_WriteMem64.find(address); if (itr != m_WriteMem64.end()) { return BP_SET; } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::WriteBPExistsInChunk(uint32_t address, uint32_t nBytes) { uint32_t endAddr = address + nBytes; for (breakpoints_t::iterator breakpoint = m_WriteMem.begin(); breakpoint != m_WriteMem.end(); breakpoint++) { uint32_t wbpAddr = breakpoint->first; if (wbpAddr >= address && wbpAddr < endAddr) { return BP_SET; } } return BP_NOT_SET; } CBreakpoints::BPSTATE CBreakpoints::ExecutionBPExists(uint32_t address, bool bRemoveTemp) { breakpoints_t::const_iterator itr = m_Execution.find(address); if (itr != m_Execution.end()) { if (itr->second) { if (bRemoveTemp) { m_Execution.erase(itr); } return BP_SET_TEMP; } return BP_SET; } return BP_NOT_SET; } void CBreakpoints::UpdateAlignedReadBP() { m_ReadMem16.clear(); m_ReadMem32.clear(); m_ReadMem64.clear(); for (breakpoints_t::const_iterator itr = m_ReadMem.begin(); itr != m_ReadMem.end(); itr++) { m_ReadMem16.insert(breakpoints_t::value_type((itr->first & ~0x1), false)); m_ReadMem32.insert(breakpoints_t::value_type((itr->first & ~0x3), false)); m_ReadMem64.insert(breakpoints_t::value_type((itr->first & ~0x7), false)); } } void CBreakpoints::UpdateAlignedWriteBP() { m_WriteMem16.clear(); m_WriteMem32.clear(); m_WriteMem64.clear(); for (breakpoints_t::const_iterator itr = m_WriteMem.begin(); itr != m_WriteMem.end(); itr++) { m_WriteMem16.insert(breakpoints_t::value_type((itr->first & ~0x1), false)); m_WriteMem32.insert(breakpoints_t::value_type((itr->first & ~0x3), false)); m_WriteMem64.insert(breakpoints_t::value_type((itr->first & ~0x7), false)); } } void CBreakpoints::ToggleMemLock(uint32_t address) { if (m_MemLocks.count(address) == 0) { m_MemLocks.insert(address); return; } m_MemLocks.erase(address); } bool CBreakpoints::MemLockExists(uint32_t address, int nBytes) { for (memlocks_t::const_iterator itr = m_MemLocks.begin(); itr != m_MemLocks.end(); itr++) { if (*itr >= address && *itr < (address + nBytes)) { return true; } } return false; } void CBreakpoints::ClearMemLocks() { m_MemLocks.clear(); } size_t CBreakpoints::NumMemLocks() { return m_MemLocks.size(); } bool CBreakpoints::HaveAnyGPRWriteBP(void) { return m_GPRWriteBP != 0; } bool CBreakpoints::HaveAnyGPRReadBP(void) { return m_GPRReadBP != 0; } bool CBreakpoints::HaveGPRWriteBP(int nReg) { return (m_GPRWriteBP & (1 << nReg)) != 0; } bool CBreakpoints::HaveGPRReadBP(int nReg) { return (m_GPRReadBP & (1 << nReg)) != 0; } void CBreakpoints::ToggleGPRWriteBP(int nReg) { m_GPRWriteBP ^= (1 << nReg); } void CBreakpoints::ToggleGPRReadBP(int nReg) { m_GPRReadBP ^= (1 << nReg); } bool CBreakpoints::HaveHIWriteBP(void) { return m_HIWriteBP; } bool CBreakpoints::HaveHIReadBP(void) { return m_HIReadBP; } bool CBreakpoints::HaveLOWriteBP(void) { return m_LOWriteBP; } bool CBreakpoints::HaveLOReadBP(void) { return m_LOReadBP; } void CBreakpoints::ToggleHIWriteBP(void) { m_HIWriteBP = !m_HIWriteBP; } void CBreakpoints::ToggleHIReadBP(void) { m_HIReadBP = !m_HIReadBP; } void CBreakpoints::ToggleLOWriteBP(void) { m_LOWriteBP = !m_LOWriteBP; } void CBreakpoints::ToggleLOReadBP(void) { m_LOReadBP = !m_LOReadBP; } void CBreakpoints::PreUpdateBP() { if (g_BaseSystem) { g_BaseSystem->ExternalEvent(SysEvent_PauseCPU_ChangingBPs); } } void CBreakpoints::PostUpdateBP() { if (g_BaseSystem) { g_BaseSystem->ExternalEvent(SysEvent_ResetRecompilerCode); g_BaseSystem->ExternalEvent(SysEvent_ResumeCPU_ChangingBPs); } }