mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 13:47:57 +03:00
MipsExecutor is now owned by MIPS CPU context.
Will help to make new breakpoint implementation simpler.
This commit is contained in:
parent
f2f0b9e6ca
commit
050bf0f854
23 changed files with 536 additions and 523 deletions
60
Source/BlockLookupOneWay.h
Normal file
60
Source/BlockLookupOneWay.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
#include "BasicBlock.h"
|
||||
|
||||
class BlockLookupOneWay
|
||||
{
|
||||
public:
|
||||
typedef CBasicBlock* BlockType;
|
||||
|
||||
BlockLookupOneWay(BlockType emptyBlock, uint32 maxAddress)
|
||||
: m_emptyBlock(emptyBlock)
|
||||
{
|
||||
m_tableSize = maxAddress / INSTRUCTION_SIZE;
|
||||
m_blockTable = new BlockType[m_tableSize];
|
||||
}
|
||||
|
||||
~BlockLookupOneWay()
|
||||
{
|
||||
delete[] m_blockTable;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < m_tableSize; i++)
|
||||
{
|
||||
m_blockTable[i] = m_emptyBlock;
|
||||
}
|
||||
}
|
||||
|
||||
void AddBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
assert(m_blockTable[address / INSTRUCTION_SIZE] == m_emptyBlock);
|
||||
m_blockTable[address / INSTRUCTION_SIZE] = block;
|
||||
}
|
||||
|
||||
void DeleteBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
assert(m_blockTable[address / INSTRUCTION_SIZE] != m_emptyBlock);
|
||||
m_blockTable[address / INSTRUCTION_SIZE] = m_emptyBlock;
|
||||
}
|
||||
|
||||
BlockType FindBlockAt(uint32 address) const
|
||||
{
|
||||
assert((address / INSTRUCTION_SIZE) < m_tableSize);
|
||||
return m_blockTable[address / INSTRUCTION_SIZE];
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
INSTRUCTION_SIZE = 4,
|
||||
};
|
||||
|
||||
BlockType m_emptyBlock = nullptr;
|
||||
BlockType* m_blockTable = nullptr;
|
||||
uint32 m_tableSize = 0;
|
||||
};
|
102
Source/BlockLookupTwoWay.h
Normal file
102
Source/BlockLookupTwoWay.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include "Types.h"
|
||||
#include "BasicBlock.h"
|
||||
|
||||
class BlockLookupTwoWay
|
||||
{
|
||||
public:
|
||||
typedef CBasicBlock* BlockType;
|
||||
|
||||
BlockLookupTwoWay(BlockType emptyBlock, uint32 maxAddress)
|
||||
: m_emptyBlock(emptyBlock)
|
||||
{
|
||||
m_subTableCount = (maxAddress + SUBTABLE_MASK) / SUBTABLE_SIZE;
|
||||
assert(m_subTableCount != 0);
|
||||
m_blockTable = new BlockType*[m_subTableCount];
|
||||
memset(m_blockTable, 0, sizeof(BlockType*) * m_subTableCount);
|
||||
}
|
||||
|
||||
~BlockLookupTwoWay()
|
||||
{
|
||||
for(unsigned int i = 0; i < m_subTableCount; i++)
|
||||
{
|
||||
auto subTable = m_blockTable[i];
|
||||
if(subTable)
|
||||
{
|
||||
delete[] subTable;
|
||||
}
|
||||
}
|
||||
delete[] m_blockTable;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < m_subTableCount; i++)
|
||||
{
|
||||
auto subTable = m_blockTable[i];
|
||||
if(subTable)
|
||||
{
|
||||
delete[] subTable;
|
||||
m_blockTable[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
uint32 hiAddress = address >> SUBTABLE_BITS;
|
||||
uint32 loAddress = address & SUBTABLE_MASK;
|
||||
assert(hiAddress < m_subTableCount);
|
||||
auto& subTable = m_blockTable[hiAddress];
|
||||
if(!subTable)
|
||||
{
|
||||
const uint32 subTableSize = SUBTABLE_SIZE / INSTRUCTION_SIZE;
|
||||
subTable = new BlockType[subTableSize];
|
||||
for(uint32 i = 0; i < subTableSize; i++)
|
||||
{
|
||||
subTable[i] = m_emptyBlock;
|
||||
}
|
||||
}
|
||||
assert(subTable[loAddress / INSTRUCTION_SIZE] == m_emptyBlock);
|
||||
subTable[loAddress / INSTRUCTION_SIZE] = block;
|
||||
}
|
||||
|
||||
void DeleteBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
uint32 hiAddress = address >> SUBTABLE_BITS;
|
||||
uint32 loAddress = address & SUBTABLE_MASK;
|
||||
assert(hiAddress < m_subTableCount);
|
||||
auto& subTable = m_blockTable[hiAddress];
|
||||
assert(subTable);
|
||||
assert(subTable[loAddress / INSTRUCTION_SIZE] != m_emptyBlock);
|
||||
subTable[loAddress / INSTRUCTION_SIZE] = m_emptyBlock;
|
||||
}
|
||||
|
||||
BlockType FindBlockAt(uint32 address) const
|
||||
{
|
||||
uint32 hiAddress = address >> SUBTABLE_BITS;
|
||||
uint32 loAddress = address & SUBTABLE_MASK;
|
||||
assert(hiAddress < m_subTableCount);
|
||||
auto& subTable = m_blockTable[hiAddress];
|
||||
if(!subTable) return m_emptyBlock;
|
||||
auto result = subTable[loAddress / INSTRUCTION_SIZE];
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
SUBTABLE_BITS = 16,
|
||||
SUBTABLE_SIZE = (1 << SUBTABLE_BITS),
|
||||
SUBTABLE_MASK = (SUBTABLE_SIZE - 1),
|
||||
INSTRUCTION_SIZE = 4,
|
||||
};
|
||||
|
||||
BlockType m_emptyBlock = nullptr;
|
||||
BlockType** m_blockTable = nullptr;
|
||||
uint32 m_subTableCount = 0;
|
||||
};
|
|
@ -118,6 +118,8 @@ set(COMMON_SRC_FILES
|
|||
AppConfig.h
|
||||
BasicBlock.cpp
|
||||
BasicBlock.h
|
||||
BlockLookupOneWay.h
|
||||
BlockLookupTwoWay.h
|
||||
ControllerInfo.cpp
|
||||
ControllerInfo.h
|
||||
COP_FPU.cpp
|
||||
|
@ -201,6 +203,7 @@ set(COMMON_SRC_FILES
|
|||
ElfFile.h
|
||||
FrameDump.cpp
|
||||
FrameDump.h
|
||||
GenericMipsExecutor.h
|
||||
gs/GsCachedArea.cpp
|
||||
gs/GsCachedArea.h
|
||||
gs/GSH_Null.cpp
|
||||
|
@ -299,7 +302,6 @@ set(COMMON_SRC_FILES
|
|||
iop/Iop_Vblank.h
|
||||
iop/IopBios.cpp
|
||||
iop/IopBios.h
|
||||
iop/IopExecutor.h
|
||||
iop/OpticalMediaDevice.cpp
|
||||
iop/OpticalMediaDevice.h
|
||||
ISO9660/DirectoryRecord.cpp
|
||||
|
|
308
Source/GenericMipsExecutor.h
Normal file
308
Source/GenericMipsExecutor.h
Normal file
|
@ -0,0 +1,308 @@
|
|||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include "MIPS.h"
|
||||
#include "BasicBlock.h"
|
||||
|
||||
#include "BlockLookupOneWay.h"
|
||||
#include "BlockLookupTwoWay.h"
|
||||
|
||||
static bool IsInsideRange(uint32 address, uint32 start, uint32 end)
|
||||
{
|
||||
return (address >= start) && (address <= end);
|
||||
}
|
||||
|
||||
typedef uint32 (*TranslateFunctionType)(CMIPS*, uint32);
|
||||
typedef std::shared_ptr<CBasicBlock> BasicBlockPtr;
|
||||
|
||||
template <typename BlockLookupType>
|
||||
class CGenericMipsExecutor : public CMipsExecutor
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_BLOCK_SIZE = 0x1000,
|
||||
};
|
||||
|
||||
CGenericMipsExecutor(CMIPS& context, uint32 maxAddress)
|
||||
: m_emptyBlock(std::make_shared<CBasicBlock>(context, MIPS_INVALID_PC, MIPS_INVALID_PC))
|
||||
, m_context(context)
|
||||
, m_maxAddress(maxAddress)
|
||||
, m_addressMask(maxAddress - 1)
|
||||
, m_blockLookup(m_emptyBlock.get(), maxAddress)
|
||||
{
|
||||
m_emptyBlock->Compile();
|
||||
assert(!context.m_emptyBlockHandler);
|
||||
context.m_emptyBlockHandler =
|
||||
[&](CMIPS* context) {
|
||||
uint32 address = m_context.m_State.nPC & m_addressMask;
|
||||
PartitionFunction(address);
|
||||
auto block = FindBlockStartingAt(address);
|
||||
assert(!block->IsEmpty());
|
||||
block->Execute();
|
||||
};
|
||||
}
|
||||
|
||||
virtual ~CGenericMipsExecutor() = default;
|
||||
|
||||
int Execute(int cycles) override
|
||||
{
|
||||
m_context.m_State.cycleQuota = cycles;
|
||||
while(m_context.m_State.nHasException == 0)
|
||||
{
|
||||
uint32 address = m_context.m_State.nPC & m_addressMask;
|
||||
auto block = m_blockLookup.FindBlockAt(address);
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
if(!m_breakpointsDisabledOnce && MustBreak()) break;
|
||||
m_breakpointsDisabledOnce = false;
|
||||
#endif
|
||||
block->Execute();
|
||||
}
|
||||
m_context.m_State.nHasException &= ~MIPS_EXECUTION_STATUS_QUOTADONE;
|
||||
return m_context.m_State.cycleQuota;
|
||||
}
|
||||
|
||||
CBasicBlock* FindBlockStartingAt(uint32 address) const
|
||||
{
|
||||
return m_blockLookup.FindBlockAt(address);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
m_blockLookup.Clear();
|
||||
m_blocks.clear();
|
||||
m_blockLinks.clear();
|
||||
m_pendingBlockLinks.clear();
|
||||
}
|
||||
|
||||
void ClearActiveBlocksInRange(uint32 start, uint32 end) override
|
||||
{
|
||||
ClearActiveBlocksInRangeInternal(start, end, nullptr);
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
bool MustBreak() const override
|
||||
{
|
||||
uint32 currentPc = m_context.m_State.nPC & m_addressMask;
|
||||
auto block = m_blockLookup.FindBlockAt(currentPc);
|
||||
for(auto breakPointAddress : m_context.m_breakpoints)
|
||||
{
|
||||
if(currentPc == breakPointAddress) return true;
|
||||
if(block != NULL)
|
||||
{
|
||||
if(breakPointAddress >= block->GetBeginAddress() && breakPointAddress <= block->GetEndAddress()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisableBreakpointsOnce() override
|
||||
{
|
||||
m_breakpointsDisabledOnce = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
//Outgoing block link
|
||||
struct BLOCK_LINK
|
||||
{
|
||||
CBasicBlock::LINK_SLOT slot;
|
||||
uint32 address;
|
||||
};
|
||||
|
||||
typedef std::list<BasicBlockPtr> BlockList;
|
||||
typedef std::multimap<uint32, BLOCK_LINK> BlockLinkMap;
|
||||
|
||||
bool HasBlockAt(uint32 address) const
|
||||
{
|
||||
auto block = m_blockLookup.FindBlockAt(address);
|
||||
return !block->IsEmpty();
|
||||
}
|
||||
|
||||
void CreateBlock(uint32 start, uint32 end)
|
||||
{
|
||||
assert(!HasBlockAt(start));
|
||||
auto block = BlockFactory(m_context, start, end);
|
||||
m_blockLookup.AddBlock(block.get());
|
||||
m_blocks.push_back(std::move(block));
|
||||
}
|
||||
|
||||
virtual BasicBlockPtr BlockFactory(CMIPS& context, uint32 start, uint32 end)
|
||||
{
|
||||
auto result = std::make_shared<CBasicBlock>(context, start, end);
|
||||
result->Compile();
|
||||
return result;
|
||||
}
|
||||
|
||||
void SetupBlockLinks(uint32 startAddress, uint32 endAddress, uint32 branchAddress)
|
||||
{
|
||||
auto block = m_blockLookup.FindBlockAt(startAddress);
|
||||
|
||||
{
|
||||
uint32 nextBlockAddress = (endAddress + 4) & m_addressMask;
|
||||
block->SetLinkTargetAddress(CBasicBlock::LINK_SLOT_NEXT, nextBlockAddress);
|
||||
auto link = std::make_pair(nextBlockAddress, BLOCK_LINK{CBasicBlock::LINK_SLOT_NEXT, startAddress});
|
||||
auto nextBlock = m_blockLookup.FindBlockAt(nextBlockAddress);
|
||||
if(!nextBlock->IsEmpty())
|
||||
{
|
||||
block->LinkBlock(CBasicBlock::LINK_SLOT_NEXT, nextBlock);
|
||||
m_blockLinks.insert(link);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pendingBlockLinks.insert(link);
|
||||
}
|
||||
}
|
||||
|
||||
if(branchAddress != 0)
|
||||
{
|
||||
branchAddress &= m_addressMask;
|
||||
block->SetLinkTargetAddress(CBasicBlock::LINK_SLOT_BRANCH, branchAddress);
|
||||
auto link = std::make_pair(branchAddress, BLOCK_LINK{CBasicBlock::LINK_SLOT_BRANCH, startAddress});
|
||||
auto branchBlock = m_blockLookup.FindBlockAt(branchAddress);
|
||||
if(!branchBlock->IsEmpty())
|
||||
{
|
||||
block->LinkBlock(CBasicBlock::LINK_SLOT_BRANCH, branchBlock);
|
||||
m_blockLinks.insert(link);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pendingBlockLinks.insert(link);
|
||||
}
|
||||
}
|
||||
|
||||
//Resolve any block links that could be valid now that block has been created
|
||||
{
|
||||
auto lowerBound = m_pendingBlockLinks.lower_bound(startAddress);
|
||||
auto upperBound = m_pendingBlockLinks.upper_bound(startAddress);
|
||||
for(auto blockLinkIterator = lowerBound; blockLinkIterator != upperBound; blockLinkIterator++)
|
||||
{
|
||||
const auto& blockLink = blockLinkIterator->second;
|
||||
auto referringBlock = m_blockLookup.FindBlockAt(blockLink.address);
|
||||
if(referringBlock->IsEmpty()) continue;
|
||||
referringBlock->LinkBlock(blockLink.slot, block);
|
||||
m_blockLinks.insert(*blockLinkIterator);
|
||||
}
|
||||
m_pendingBlockLinks.erase(lowerBound, upperBound);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PartitionFunction(uint32 startAddress)
|
||||
{
|
||||
uint32 endAddress = startAddress + MAX_BLOCK_SIZE;
|
||||
uint32 branchAddress = 0;
|
||||
for(uint32 address = startAddress; address < endAddress; address += 4)
|
||||
{
|
||||
uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
|
||||
auto branchType = m_context.m_pArch->IsInstructionBranch(&m_context, address, opcode);
|
||||
if(branchType == MIPS_BRANCH_NORMAL)
|
||||
{
|
||||
branchAddress = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, address, opcode);
|
||||
endAddress = address + 4;
|
||||
break;
|
||||
}
|
||||
else if(branchType == MIPS_BRANCH_NODELAY)
|
||||
{
|
||||
endAddress = address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert((endAddress - startAddress) <= MAX_BLOCK_SIZE);
|
||||
assert(endAddress <= m_maxAddress);
|
||||
CreateBlock(startAddress, endAddress);
|
||||
SetupBlockLinks(startAddress, endAddress, branchAddress);
|
||||
}
|
||||
|
||||
//Unlink and removes block from all of our bookkeeping structures
|
||||
void OrphanBlock(CBasicBlock* block)
|
||||
{
|
||||
auto orphanBlockLinkSlot =
|
||||
[&](CBasicBlock::LINK_SLOT linkSlot) {
|
||||
auto slotSearch =
|
||||
[&](const std::pair<uint32, BLOCK_LINK>& link) {
|
||||
return (link.second.address == block->GetBeginAddress()) &&
|
||||
(link.second.slot == linkSlot);
|
||||
};
|
||||
uint32 linkTargetAddress = block->GetLinkTargetAddress(linkSlot);
|
||||
//Check if block has this specific link slot
|
||||
if(linkTargetAddress != MIPS_INVALID_PC)
|
||||
{
|
||||
//If it has that link slot, it's either linked or pending to be linked
|
||||
auto slotIterator = std::find_if(m_blockLinks.begin(), m_blockLinks.end(), slotSearch);
|
||||
if(slotIterator != std::end(m_blockLinks))
|
||||
{
|
||||
block->UnlinkBlock(linkSlot);
|
||||
m_blockLinks.erase(slotIterator);
|
||||
}
|
||||
else
|
||||
{
|
||||
slotIterator = std::find_if(m_pendingBlockLinks.begin(), m_pendingBlockLinks.end(), slotSearch);
|
||||
assert(slotIterator != std::end(m_pendingBlockLinks));
|
||||
m_pendingBlockLinks.erase(slotIterator);
|
||||
}
|
||||
}
|
||||
};
|
||||
orphanBlockLinkSlot(CBasicBlock::LINK_SLOT_NEXT);
|
||||
orphanBlockLinkSlot(CBasicBlock::LINK_SLOT_BRANCH);
|
||||
}
|
||||
|
||||
void ClearActiveBlocksInRangeInternal(uint32 start, uint32 end, CBasicBlock* protectedBlock)
|
||||
{
|
||||
//Widen scan range since blocks starting before the range can end in the range
|
||||
uint32 scanStart = static_cast<uint32>(std::max<int64>(0, static_cast<uint64>(start) - MAX_BLOCK_SIZE));
|
||||
uint32 scanEnd = end;
|
||||
assert(scanEnd > scanStart);
|
||||
|
||||
std::set<CBasicBlock*> clearedBlocks;
|
||||
for(uint32 address = scanStart; address < scanEnd; address += 4)
|
||||
{
|
||||
auto block = m_blockLookup.FindBlockAt(address);
|
||||
if(block->IsEmpty()) continue;
|
||||
if(block == protectedBlock) continue;
|
||||
if(!IsInsideRange(block->GetBeginAddress(), start, end) && !IsInsideRange(block->GetEndAddress(), start, end)) continue;
|
||||
clearedBlocks.insert(block);
|
||||
m_blockLookup.DeleteBlock(block);
|
||||
}
|
||||
|
||||
//Remove pending block link entries for the blocks that are about to be cleared
|
||||
for(auto& block : clearedBlocks)
|
||||
{
|
||||
OrphanBlock(block);
|
||||
}
|
||||
|
||||
//Undo all stale links
|
||||
for(auto& block : clearedBlocks)
|
||||
{
|
||||
auto lowerBound = m_blockLinks.lower_bound(block->GetBeginAddress());
|
||||
auto upperBound = m_blockLinks.upper_bound(block->GetBeginAddress());
|
||||
for(auto blockLinkIterator = lowerBound; blockLinkIterator != upperBound; blockLinkIterator++)
|
||||
{
|
||||
const auto& blockLink = blockLinkIterator->second;
|
||||
auto referringBlock = m_blockLookup.FindBlockAt(blockLink.address);
|
||||
if(referringBlock->IsEmpty()) continue;
|
||||
referringBlock->UnlinkBlock(blockLink.slot);
|
||||
m_pendingBlockLinks.insert(*blockLinkIterator);
|
||||
}
|
||||
m_blockLinks.erase(lowerBound, upperBound);
|
||||
}
|
||||
|
||||
if(!clearedBlocks.empty())
|
||||
{
|
||||
m_blocks.remove_if([&](const BasicBlockPtr& block) { return clearedBlocks.find(block.get()) != std::end(clearedBlocks); });
|
||||
}
|
||||
}
|
||||
|
||||
BlockList m_blocks;
|
||||
BasicBlockPtr m_emptyBlock;
|
||||
BlockLinkMap m_blockLinks;
|
||||
BlockLinkMap m_pendingBlockLinks;
|
||||
CMIPS& m_context;
|
||||
uint32 m_maxAddress = 0;
|
||||
uint32 m_addressMask = 0;
|
||||
|
||||
BlockLookupType m_blockLookup;
|
||||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
bool m_breakpointsDisabledOnce = false;
|
||||
#endif
|
||||
};
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Types.h"
|
||||
#include "MemoryMap.h"
|
||||
#include "MipsExecutor.h"
|
||||
#include "MIPSArchitecture.h"
|
||||
#include "MIPSCoprocessor.h"
|
||||
#include "MIPSAnalysis.h"
|
||||
|
@ -145,6 +146,7 @@ public:
|
|||
CMIPSArchitecture* m_pArch = nullptr;
|
||||
CMIPSCoprocessor* m_pCOP[4];
|
||||
CMemoryMap* m_pMemoryMap = nullptr;
|
||||
std::unique_ptr<CMipsExecutor> m_executor;
|
||||
BreakpointSet m_breakpoints;
|
||||
|
||||
CMIPSAnalysis* m_analysis = nullptr;
|
||||
|
|
|
@ -1,458 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include "MIPS.h"
|
||||
#include "BasicBlock.h"
|
||||
#include "Types.h"
|
||||
|
||||
static bool IsInsideRange(uint32 address, uint32 start, uint32 end)
|
||||
{
|
||||
return (address >= start) && (address <= end);
|
||||
}
|
||||
|
||||
class BlockLookupOneWay
|
||||
{
|
||||
public:
|
||||
typedef CBasicBlock* BlockType;
|
||||
|
||||
BlockLookupOneWay(BlockType emptyBlock, uint32 maxAddress)
|
||||
: m_emptyBlock(emptyBlock)
|
||||
{
|
||||
m_tableSize = maxAddress / INSTRUCTION_SIZE;
|
||||
m_blockTable = new BlockType[m_tableSize];
|
||||
}
|
||||
|
||||
~BlockLookupOneWay()
|
||||
{
|
||||
delete[] m_blockTable;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < m_tableSize; i++)
|
||||
{
|
||||
m_blockTable[i] = m_emptyBlock;
|
||||
}
|
||||
}
|
||||
|
||||
void AddBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
assert(m_blockTable[address / INSTRUCTION_SIZE] == m_emptyBlock);
|
||||
m_blockTable[address / INSTRUCTION_SIZE] = block;
|
||||
}
|
||||
|
||||
void DeleteBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
assert(m_blockTable[address / INSTRUCTION_SIZE] != m_emptyBlock);
|
||||
m_blockTable[address / INSTRUCTION_SIZE] = m_emptyBlock;
|
||||
}
|
||||
|
||||
BlockType FindBlockAt(uint32 address) const
|
||||
{
|
||||
assert((address / INSTRUCTION_SIZE) < m_tableSize);
|
||||
return m_blockTable[address / INSTRUCTION_SIZE];
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
INSTRUCTION_SIZE = 4,
|
||||
};
|
||||
|
||||
BlockType m_emptyBlock = nullptr;
|
||||
BlockType* m_blockTable = nullptr;
|
||||
uint32 m_tableSize = 0;
|
||||
};
|
||||
|
||||
class BlockLookupTwoWay
|
||||
{
|
||||
public:
|
||||
typedef CBasicBlock* BlockType;
|
||||
|
||||
BlockLookupTwoWay(BlockType emptyBlock, uint32 maxAddress)
|
||||
: m_emptyBlock(emptyBlock)
|
||||
{
|
||||
m_subTableCount = (maxAddress + SUBTABLE_MASK) / SUBTABLE_SIZE;
|
||||
assert(m_subTableCount != 0);
|
||||
m_blockTable = new BlockType*[m_subTableCount];
|
||||
memset(m_blockTable, 0, sizeof(BlockType*) * m_subTableCount);
|
||||
}
|
||||
|
||||
~BlockLookupTwoWay()
|
||||
{
|
||||
for(unsigned int i = 0; i < m_subTableCount; i++)
|
||||
{
|
||||
auto subTable = m_blockTable[i];
|
||||
if(subTable)
|
||||
{
|
||||
delete[] subTable;
|
||||
}
|
||||
}
|
||||
delete[] m_blockTable;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < m_subTableCount; i++)
|
||||
{
|
||||
auto subTable = m_blockTable[i];
|
||||
if(subTable)
|
||||
{
|
||||
delete[] subTable;
|
||||
m_blockTable[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
uint32 hiAddress = address >> SUBTABLE_BITS;
|
||||
uint32 loAddress = address & SUBTABLE_MASK;
|
||||
assert(hiAddress < m_subTableCount);
|
||||
auto& subTable = m_blockTable[hiAddress];
|
||||
if(!subTable)
|
||||
{
|
||||
const uint32 subTableSize = SUBTABLE_SIZE / INSTRUCTION_SIZE;
|
||||
subTable = new BlockType[subTableSize];
|
||||
for(uint32 i = 0; i < subTableSize; i++)
|
||||
{
|
||||
subTable[i] = m_emptyBlock;
|
||||
}
|
||||
}
|
||||
assert(subTable[loAddress / INSTRUCTION_SIZE] == m_emptyBlock);
|
||||
subTable[loAddress / INSTRUCTION_SIZE] = block;
|
||||
}
|
||||
|
||||
void DeleteBlock(BlockType block)
|
||||
{
|
||||
uint32 address = block->GetBeginAddress();
|
||||
uint32 hiAddress = address >> SUBTABLE_BITS;
|
||||
uint32 loAddress = address & SUBTABLE_MASK;
|
||||
assert(hiAddress < m_subTableCount);
|
||||
auto& subTable = m_blockTable[hiAddress];
|
||||
assert(subTable);
|
||||
assert(subTable[loAddress / INSTRUCTION_SIZE] != m_emptyBlock);
|
||||
subTable[loAddress / INSTRUCTION_SIZE] = m_emptyBlock;
|
||||
}
|
||||
|
||||
BlockType FindBlockAt(uint32 address) const
|
||||
{
|
||||
uint32 hiAddress = address >> SUBTABLE_BITS;
|
||||
uint32 loAddress = address & SUBTABLE_MASK;
|
||||
assert(hiAddress < m_subTableCount);
|
||||
auto& subTable = m_blockTable[hiAddress];
|
||||
if(!subTable) return m_emptyBlock;
|
||||
auto result = subTable[loAddress / INSTRUCTION_SIZE];
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
SUBTABLE_BITS = 16,
|
||||
SUBTABLE_SIZE = (1 << SUBTABLE_BITS),
|
||||
SUBTABLE_MASK = (SUBTABLE_SIZE - 1),
|
||||
INSTRUCTION_SIZE = 4,
|
||||
};
|
||||
|
||||
BlockType m_emptyBlock = nullptr;
|
||||
BlockType** m_blockTable = nullptr;
|
||||
uint32 m_subTableCount = 0;
|
||||
};
|
||||
|
||||
typedef uint32 (*TranslateFunctionType)(CMIPS*, uint32);
|
||||
typedef std::shared_ptr<CBasicBlock> BasicBlockPtr;
|
||||
|
||||
template <typename BlockLookupType>
|
||||
class CMipsExecutor
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_BLOCK_SIZE = 0x1000,
|
||||
};
|
||||
|
||||
CMipsExecutor(CMIPS& context, uint32 maxAddress)
|
||||
: m_emptyBlock(std::make_shared<CBasicBlock>(context, MIPS_INVALID_PC, MIPS_INVALID_PC))
|
||||
, m_context(context)
|
||||
, m_maxAddress(maxAddress)
|
||||
, m_addressMask(maxAddress - 1)
|
||||
, m_blockLookup(m_emptyBlock.get(), maxAddress)
|
||||
{
|
||||
m_emptyBlock->Compile();
|
||||
assert(!context.m_emptyBlockHandler);
|
||||
context.m_emptyBlockHandler =
|
||||
[&](CMIPS* context) {
|
||||
uint32 address = m_context.m_State.nPC & m_addressMask;
|
||||
PartitionFunction(address);
|
||||
auto block = FindBlockStartingAt(address);
|
||||
assert(!block->IsEmpty());
|
||||
block->Execute();
|
||||
};
|
||||
}
|
||||
|
||||
virtual ~CMipsExecutor() = default;
|
||||
|
||||
int Execute(int cycles)
|
||||
{
|
||||
m_context.m_State.cycleQuota = cycles;
|
||||
while(m_context.m_State.nHasException == 0)
|
||||
{
|
||||
uint32 address = m_context.m_State.nPC & m_addressMask;
|
||||
auto block = m_blockLookup.FindBlockAt(address);
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
if(!m_breakpointsDisabledOnce && MustBreak()) break;
|
||||
m_breakpointsDisabledOnce = false;
|
||||
#endif
|
||||
block->Execute();
|
||||
}
|
||||
m_context.m_State.nHasException &= ~MIPS_EXECUTION_STATUS_QUOTADONE;
|
||||
return m_context.m_State.cycleQuota;
|
||||
}
|
||||
|
||||
CBasicBlock* FindBlockStartingAt(uint32 address) const
|
||||
{
|
||||
return m_blockLookup.FindBlockAt(address);
|
||||
}
|
||||
|
||||
virtual void Reset()
|
||||
{
|
||||
m_blockLookup.Clear();
|
||||
m_blocks.clear();
|
||||
m_blockLinks.clear();
|
||||
m_pendingBlockLinks.clear();
|
||||
}
|
||||
|
||||
virtual void ClearActiveBlocksInRange(uint32 start, uint32 end)
|
||||
{
|
||||
ClearActiveBlocksInRangeInternal(start, end, nullptr);
|
||||
}
|
||||
virtual void Reset() = 0;
|
||||
virtual int Execute(int) = 0;
|
||||
virtual void ClearActiveBlocksInRange(uint32 start, uint32 end) = 0;
|
||||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
bool MustBreak() const
|
||||
{
|
||||
uint32 currentPc = m_context.m_State.nPC & m_addressMask;
|
||||
auto block = m_blockLookup.FindBlockAt(currentPc);
|
||||
for(auto breakPointAddress : m_context.m_breakpoints)
|
||||
{
|
||||
if(currentPc == breakPointAddress) return true;
|
||||
if(block != NULL)
|
||||
{
|
||||
if(breakPointAddress >= block->GetBeginAddress() && breakPointAddress <= block->GetEndAddress()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisableBreakpointsOnce()
|
||||
{
|
||||
m_breakpointsDisabledOnce = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
//Outgoing block link
|
||||
struct BLOCK_LINK
|
||||
{
|
||||
CBasicBlock::LINK_SLOT slot;
|
||||
uint32 address;
|
||||
};
|
||||
|
||||
typedef std::list<BasicBlockPtr> BlockList;
|
||||
typedef std::multimap<uint32, BLOCK_LINK> BlockLinkMap;
|
||||
|
||||
bool HasBlockAt(uint32 address) const
|
||||
{
|
||||
auto block = m_blockLookup.FindBlockAt(address);
|
||||
return !block->IsEmpty();
|
||||
}
|
||||
|
||||
void CreateBlock(uint32 start, uint32 end)
|
||||
{
|
||||
assert(!HasBlockAt(start));
|
||||
auto block = BlockFactory(m_context, start, end);
|
||||
m_blockLookup.AddBlock(block.get());
|
||||
m_blocks.push_back(std::move(block));
|
||||
}
|
||||
|
||||
virtual BasicBlockPtr BlockFactory(CMIPS& context, uint32 start, uint32 end)
|
||||
{
|
||||
auto result = std::make_shared<CBasicBlock>(context, start, end);
|
||||
result->Compile();
|
||||
return result;
|
||||
}
|
||||
|
||||
void SetupBlockLinks(uint32 startAddress, uint32 endAddress, uint32 branchAddress)
|
||||
{
|
||||
auto block = m_blockLookup.FindBlockAt(startAddress);
|
||||
|
||||
{
|
||||
uint32 nextBlockAddress = (endAddress + 4) & m_addressMask;
|
||||
block->SetLinkTargetAddress(CBasicBlock::LINK_SLOT_NEXT, nextBlockAddress);
|
||||
auto link = std::make_pair(nextBlockAddress, BLOCK_LINK{CBasicBlock::LINK_SLOT_NEXT, startAddress});
|
||||
auto nextBlock = m_blockLookup.FindBlockAt(nextBlockAddress);
|
||||
if(!nextBlock->IsEmpty())
|
||||
{
|
||||
block->LinkBlock(CBasicBlock::LINK_SLOT_NEXT, nextBlock);
|
||||
m_blockLinks.insert(link);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pendingBlockLinks.insert(link);
|
||||
}
|
||||
}
|
||||
|
||||
if(branchAddress != 0)
|
||||
{
|
||||
branchAddress &= m_addressMask;
|
||||
block->SetLinkTargetAddress(CBasicBlock::LINK_SLOT_BRANCH, branchAddress);
|
||||
auto link = std::make_pair(branchAddress, BLOCK_LINK{CBasicBlock::LINK_SLOT_BRANCH, startAddress});
|
||||
auto branchBlock = m_blockLookup.FindBlockAt(branchAddress);
|
||||
if(!branchBlock->IsEmpty())
|
||||
{
|
||||
block->LinkBlock(CBasicBlock::LINK_SLOT_BRANCH, branchBlock);
|
||||
m_blockLinks.insert(link);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pendingBlockLinks.insert(link);
|
||||
}
|
||||
}
|
||||
|
||||
//Resolve any block links that could be valid now that block has been created
|
||||
{
|
||||
auto lowerBound = m_pendingBlockLinks.lower_bound(startAddress);
|
||||
auto upperBound = m_pendingBlockLinks.upper_bound(startAddress);
|
||||
for(auto blockLinkIterator = lowerBound; blockLinkIterator != upperBound; blockLinkIterator++)
|
||||
{
|
||||
const auto& blockLink = blockLinkIterator->second;
|
||||
auto referringBlock = m_blockLookup.FindBlockAt(blockLink.address);
|
||||
if(referringBlock->IsEmpty()) continue;
|
||||
referringBlock->LinkBlock(blockLink.slot, block);
|
||||
m_blockLinks.insert(*blockLinkIterator);
|
||||
}
|
||||
m_pendingBlockLinks.erase(lowerBound, upperBound);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PartitionFunction(uint32 startAddress)
|
||||
{
|
||||
uint32 endAddress = startAddress + MAX_BLOCK_SIZE;
|
||||
uint32 branchAddress = 0;
|
||||
for(uint32 address = startAddress; address < endAddress; address += 4)
|
||||
{
|
||||
uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
|
||||
auto branchType = m_context.m_pArch->IsInstructionBranch(&m_context, address, opcode);
|
||||
if(branchType == MIPS_BRANCH_NORMAL)
|
||||
{
|
||||
branchAddress = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, address, opcode);
|
||||
endAddress = address + 4;
|
||||
break;
|
||||
}
|
||||
else if(branchType == MIPS_BRANCH_NODELAY)
|
||||
{
|
||||
endAddress = address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert((endAddress - startAddress) <= MAX_BLOCK_SIZE);
|
||||
assert(endAddress <= m_maxAddress);
|
||||
CreateBlock(startAddress, endAddress);
|
||||
SetupBlockLinks(startAddress, endAddress, branchAddress);
|
||||
}
|
||||
|
||||
//Unlink and removes block from all of our bookkeeping structures
|
||||
void OrphanBlock(CBasicBlock* block)
|
||||
{
|
||||
auto orphanBlockLinkSlot =
|
||||
[&](CBasicBlock::LINK_SLOT linkSlot) {
|
||||
auto slotSearch =
|
||||
[&](const std::pair<uint32, BLOCK_LINK>& link) {
|
||||
return (link.second.address == block->GetBeginAddress()) &&
|
||||
(link.second.slot == linkSlot);
|
||||
};
|
||||
uint32 linkTargetAddress = block->GetLinkTargetAddress(linkSlot);
|
||||
//Check if block has this specific link slot
|
||||
if(linkTargetAddress != MIPS_INVALID_PC)
|
||||
{
|
||||
//If it has that link slot, it's either linked or pending to be linked
|
||||
auto slotIterator = std::find_if(m_blockLinks.begin(), m_blockLinks.end(), slotSearch);
|
||||
if(slotIterator != std::end(m_blockLinks))
|
||||
{
|
||||
block->UnlinkBlock(linkSlot);
|
||||
m_blockLinks.erase(slotIterator);
|
||||
}
|
||||
else
|
||||
{
|
||||
slotIterator = std::find_if(m_pendingBlockLinks.begin(), m_pendingBlockLinks.end(), slotSearch);
|
||||
assert(slotIterator != std::end(m_pendingBlockLinks));
|
||||
m_pendingBlockLinks.erase(slotIterator);
|
||||
}
|
||||
}
|
||||
};
|
||||
orphanBlockLinkSlot(CBasicBlock::LINK_SLOT_NEXT);
|
||||
orphanBlockLinkSlot(CBasicBlock::LINK_SLOT_BRANCH);
|
||||
}
|
||||
|
||||
void ClearActiveBlocksInRangeInternal(uint32 start, uint32 end, CBasicBlock* protectedBlock)
|
||||
{
|
||||
//Widen scan range since blocks starting before the range can end in the range
|
||||
uint32 scanStart = static_cast<uint32>(std::max<int64>(0, static_cast<uint64>(start) - MAX_BLOCK_SIZE));
|
||||
uint32 scanEnd = end;
|
||||
assert(scanEnd > scanStart);
|
||||
|
||||
std::set<CBasicBlock*> clearedBlocks;
|
||||
for(uint32 address = scanStart; address < scanEnd; address += 4)
|
||||
{
|
||||
auto block = m_blockLookup.FindBlockAt(address);
|
||||
if(block->IsEmpty()) continue;
|
||||
if(block == protectedBlock) continue;
|
||||
if(!IsInsideRange(block->GetBeginAddress(), start, end) && !IsInsideRange(block->GetEndAddress(), start, end)) continue;
|
||||
clearedBlocks.insert(block);
|
||||
m_blockLookup.DeleteBlock(block);
|
||||
}
|
||||
|
||||
//Remove pending block link entries for the blocks that are about to be cleared
|
||||
for(auto& block : clearedBlocks)
|
||||
{
|
||||
OrphanBlock(block);
|
||||
}
|
||||
|
||||
//Undo all stale links
|
||||
for(auto& block : clearedBlocks)
|
||||
{
|
||||
auto lowerBound = m_blockLinks.lower_bound(block->GetBeginAddress());
|
||||
auto upperBound = m_blockLinks.upper_bound(block->GetBeginAddress());
|
||||
for(auto blockLinkIterator = lowerBound; blockLinkIterator != upperBound; blockLinkIterator++)
|
||||
{
|
||||
const auto& blockLink = blockLinkIterator->second;
|
||||
auto referringBlock = m_blockLookup.FindBlockAt(blockLink.address);
|
||||
if(referringBlock->IsEmpty()) continue;
|
||||
referringBlock->UnlinkBlock(blockLink.slot);
|
||||
m_pendingBlockLinks.insert(*blockLinkIterator);
|
||||
}
|
||||
m_blockLinks.erase(lowerBound, upperBound);
|
||||
}
|
||||
|
||||
if(!clearedBlocks.empty())
|
||||
{
|
||||
m_blocks.remove_if([&](const BasicBlockPtr& block) { return clearedBlocks.find(block.get()) != std::end(clearedBlocks); });
|
||||
}
|
||||
}
|
||||
|
||||
BlockList m_blocks;
|
||||
BasicBlockPtr m_emptyBlock;
|
||||
BlockLinkMap m_blockLinks;
|
||||
BlockLinkMap m_pendingBlockLinks;
|
||||
CMIPS& m_context;
|
||||
uint32 m_maxAddress = 0;
|
||||
uint32 m_addressMask = 0;
|
||||
|
||||
BlockLookupType m_blockLookup;
|
||||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
bool m_breakpointsDisabledOnce = false;
|
||||
virtual bool MustBreak() const = 0;
|
||||
virtual void DisableBreakpointsOnce() = 0;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "PS2VM.h"
|
||||
#include "PS2VM_Preferences.h"
|
||||
#include "ee/PS2OS.h"
|
||||
#include "ee/EeExecutor.h"
|
||||
#include "Ps2Const.h"
|
||||
#include "iop/Iop_SifManPs2.h"
|
||||
#include "StdStream.h"
|
||||
|
@ -470,9 +471,9 @@ void CPS2VM::PauseImpl()
|
|||
void CPS2VM::ResumeImpl()
|
||||
{
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
m_ee->m_executor.DisableBreakpointsOnce();
|
||||
m_iop->m_executor.DisableBreakpointsOnce();
|
||||
m_ee->m_vpu1->DisableBreakpointsOnce();
|
||||
m_ee->m_EE.m_executor->DisableBreakpointsOnce();
|
||||
m_iop->m_cpu.m_executor->DisableBreakpointsOnce();
|
||||
m_ee->m_VU1.m_executor->DisableBreakpointsOnce();
|
||||
#endif
|
||||
m_nStatus = RUNNING;
|
||||
}
|
||||
|
@ -577,7 +578,7 @@ void CPS2VM::UpdateEe()
|
|||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
if(m_singleStepEe) break;
|
||||
if(m_ee->m_executor.MustBreak()) break;
|
||||
if(m_ee->m_EE.m_executor->MustBreak()) break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -608,7 +609,7 @@ void CPS2VM::UpdateIop()
|
|||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
if(m_singleStepIop) break;
|
||||
if(m_iop->m_executor.MustBreak()) break;
|
||||
if(m_iop->m_cpu.m_executor->MustBreak()) break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -715,7 +716,7 @@ void CPS2VM::EmuThread()
|
|||
#ifdef PROFILE
|
||||
CProfilerZone profilerZone(m_otherProfilerZone);
|
||||
#endif
|
||||
m_ee->m_executor.AddExceptionHandler();
|
||||
static_cast<CEeExecutor*>(m_ee->m_EE.m_executor.get())->AddExceptionHandler();
|
||||
while(1)
|
||||
{
|
||||
while(m_mailBox.IsPending())
|
||||
|
@ -792,9 +793,9 @@ void CPS2VM::EmuThread()
|
|||
}
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
if(
|
||||
m_ee->m_executor.MustBreak() ||
|
||||
m_iop->m_executor.MustBreak() ||
|
||||
m_ee->m_vpu1->MustBreak() ||
|
||||
m_ee->m_EE.m_executor->MustBreak() ||
|
||||
m_iop->m_cpu.m_executor->MustBreak() ||
|
||||
m_ee->m_VU1.m_executor->MustBreak() ||
|
||||
m_singleStepEe || m_singleStepIop || m_singleStepVu0 || m_singleStepVu1)
|
||||
{
|
||||
m_nStatus = PAUSED;
|
||||
|
@ -808,5 +809,5 @@ void CPS2VM::EmuThread()
|
|||
#endif
|
||||
}
|
||||
}
|
||||
m_ee->m_executor.RemoveExceptionHandler();
|
||||
static_cast<CEeExecutor*>(m_ee->m_EE.m_executor.get())->RemoveExceptionHandler();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
static CEeExecutor* g_eeExecutor = nullptr;
|
||||
|
||||
CEeExecutor::CEeExecutor(CMIPS& context, uint8* ram)
|
||||
: CMipsExecutor(context, 0x20000000)
|
||||
: CGenericMipsExecutor(context, 0x20000000)
|
||||
, m_ram(ram)
|
||||
{
|
||||
m_pageSize = framework_getpagesize();
|
||||
|
@ -96,7 +96,7 @@ void CEeExecutor::RemoveExceptionHandler()
|
|||
void CEeExecutor::Reset()
|
||||
{
|
||||
SetMemoryProtected(m_ram, PS2::EE_RAM_SIZE, false);
|
||||
CMipsExecutor::Reset();
|
||||
CGenericMipsExecutor::Reset();
|
||||
}
|
||||
|
||||
void CEeExecutor::ClearActiveBlocksInRange(uint32 start, uint32 end)
|
||||
|
@ -117,7 +117,7 @@ BasicBlockPtr CEeExecutor::BlockFactory(CMIPS& context, uint32 start, uint32 end
|
|||
{
|
||||
SetMemoryProtected(m_ram + start, end - start + 4, true);
|
||||
}
|
||||
return CMipsExecutor::BlockFactory(context, start, end);
|
||||
return CGenericMipsExecutor::BlockFactory(context, start, end);
|
||||
}
|
||||
|
||||
bool CEeExecutor::HandleAccessFault(intptr_t ptr)
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "../MipsExecutor.h"
|
||||
#include "../GenericMipsExecutor.h"
|
||||
|
||||
class CEeExecutor : public CMipsExecutor<BlockLookupTwoWay>
|
||||
class CEeExecutor : public CGenericMipsExecutor<BlockLookupTwoWay>
|
||||
{
|
||||
public:
|
||||
CEeExecutor(CMIPS&, uint8*);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "Ee_SubSystem.h"
|
||||
#include "EeExecutor.h"
|
||||
#include "VuExecutor.h"
|
||||
#include "../Ps2Const.h"
|
||||
#include "../Log.h"
|
||||
#include "../MemoryStateFile.h"
|
||||
|
@ -34,7 +36,6 @@ CSubSystem::CSubSystem(uint8* iopRam, CIopBios& iopBios)
|
|||
, m_EE(MEMORYMAP_ENDIAN_LSBF)
|
||||
, m_VU0(MEMORYMAP_ENDIAN_LSBF)
|
||||
, m_VU1(MEMORYMAP_ENDIAN_LSBF)
|
||||
, m_executor(m_EE, m_ram)
|
||||
, m_dmac(m_ram, m_spr, m_vuMem0, m_EE)
|
||||
, m_gif(m_gs, m_ram, m_spr)
|
||||
, m_sif(m_dmac, m_ram, iopRam)
|
||||
|
@ -60,6 +61,8 @@ CSubSystem::CSubSystem(uint8* iopRam, CIopBios& iopBios)
|
|||
|
||||
//EmotionEngine context setup
|
||||
{
|
||||
m_EE.m_executor = std::make_unique<CEeExecutor>(m_EE, m_ram);
|
||||
|
||||
//Read map
|
||||
m_EE.m_pMemoryMap->InsertReadMap(0x00000000, 0x01FFFFFF, m_ram, 0x00);
|
||||
m_EE.m_pMemoryMap->InsertReadMap(PS2::EE_SPR_ADDR, PS2::EE_SPR_ADDR + PS2::EE_SPR_SIZE - 1, m_spr, 0x01);
|
||||
|
@ -96,6 +99,8 @@ CSubSystem::CSubSystem(uint8* iopRam, CIopBios& iopBios)
|
|||
|
||||
//Vector Unit 0 context setup
|
||||
{
|
||||
m_VU0.m_executor = std::make_unique<CVuExecutor>(m_VU0, PS2::MICROMEM0SIZE);
|
||||
|
||||
m_VU0.m_pMemoryMap->InsertReadMap(0x00000000, 0x00000FFF, m_vuMem0, 0x01);
|
||||
m_VU0.m_pMemoryMap->InsertReadMap(0x00001000, 0x00001FFF, m_vuMem0, 0x02);
|
||||
m_VU0.m_pMemoryMap->InsertReadMap(0x00002000, 0x00002FFF, m_vuMem0, 0x03);
|
||||
|
@ -116,6 +121,8 @@ CSubSystem::CSubSystem(uint8* iopRam, CIopBios& iopBios)
|
|||
|
||||
//Vector Unit 1 context setup
|
||||
{
|
||||
m_VU1.m_executor = std::make_unique<CVuExecutor>(m_VU1, PS2::MICROMEM1SIZE);
|
||||
|
||||
m_VU1.m_pMemoryMap->InsertReadMap(0x00000000, 0x00003FFF, m_vuMem1, 0x00);
|
||||
m_VU1.m_pMemoryMap->InsertReadMap(0x00008000, 0x00008FFF, std::bind(&CSubSystem::Vu1IoPortReadHandler, this, PLACEHOLDER_1), 0x01);
|
||||
|
||||
|
@ -147,7 +154,7 @@ CSubSystem::CSubSystem(uint8* iopRam, CIopBios& iopBios)
|
|||
|
||||
CSubSystem::~CSubSystem()
|
||||
{
|
||||
m_executor.Reset();
|
||||
m_EE.m_executor->Reset();
|
||||
delete m_os;
|
||||
framework_aligned_free(m_ram);
|
||||
delete[] m_bios;
|
||||
|
@ -172,7 +179,7 @@ void CSubSystem::SetVpu1(std::shared_ptr<CVpu> newVpu1)
|
|||
void CSubSystem::Reset()
|
||||
{
|
||||
m_os->Release();
|
||||
m_executor.Reset();
|
||||
m_EE.m_executor->Reset();
|
||||
|
||||
memset(m_ram, 0, PS2::EE_RAM_SIZE);
|
||||
memset(m_spr, 0, PS2::EE_SPR_SIZE);
|
||||
|
@ -228,7 +235,7 @@ int CSubSystem::ExecuteCpu(int quota)
|
|||
}
|
||||
else if(!m_EE.m_State.nHasException)
|
||||
{
|
||||
executed = (quota - m_executor.Execute(quota));
|
||||
executed = (quota - m_EE.m_executor->Execute(quota));
|
||||
}
|
||||
if(m_EE.m_State.nHasException)
|
||||
{
|
||||
|
@ -380,7 +387,7 @@ void CSubSystem::LoadState(Framework::CZipArchiveReader& archive)
|
|||
m_timer.LoadState(archive);
|
||||
m_gif.LoadState(archive);
|
||||
|
||||
m_executor.Reset();
|
||||
m_EE.m_executor->Reset();
|
||||
}
|
||||
|
||||
uint32 CSubSystem::IOPortReadHandler(uint32 nAddress)
|
||||
|
@ -652,7 +659,7 @@ void CSubSystem::CheckPendingInterrupts()
|
|||
m_intc.IsInterruptPending()
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
// && !m_singleStepEe
|
||||
&& !m_executor.MustBreak()
|
||||
&& !m_EE.m_executor->MustBreak()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
|
@ -663,7 +670,7 @@ void CSubSystem::CheckPendingInterrupts()
|
|||
|
||||
void CSubSystem::FlushInstructionCache()
|
||||
{
|
||||
m_executor.Reset();
|
||||
m_EE.m_executor->Reset();
|
||||
}
|
||||
|
||||
void CSubSystem::LoadBIOS()
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "AlignedAlloc.h"
|
||||
#include "../COP_SCU.h"
|
||||
#include "../COP_FPU.h"
|
||||
#include "EeExecutor.h"
|
||||
#include "DMAC.h"
|
||||
#include "GIF.h"
|
||||
#include "SIF.h"
|
||||
|
@ -66,7 +65,6 @@ namespace Ee
|
|||
CMIPS m_EE;
|
||||
CMIPS m_VU0;
|
||||
CMIPS m_VU1;
|
||||
CEeExecutor m_executor;
|
||||
|
||||
void* operator new(size_t allocSize)
|
||||
{
|
||||
|
|
|
@ -18,7 +18,6 @@ CVpu::CVpu(unsigned int number, const VPUINIT& vpuInit, CGIF& gif, CINTC& intc,
|
|||
, m_vuMemSize((number == 0) ? PS2::VUMEM0SIZE : PS2::VUMEM1SIZE)
|
||||
, m_ctx(vpuInit.context)
|
||||
, m_gif(gif)
|
||||
, m_executor(*vpuInit.context, (number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE)
|
||||
, m_vuProfilerZone(CProfiler::GetInstance().RegisterZone("VU"))
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
, m_microMemMiniState(new uint8[(number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE])
|
||||
|
@ -45,7 +44,7 @@ void CVpu::Execute(int32 quota)
|
|||
CProfilerZone profilerZone(m_vuProfilerZone);
|
||||
#endif
|
||||
|
||||
m_executor.Execute(quota);
|
||||
m_ctx->m_executor->Execute(quota);
|
||||
if(m_ctx->m_State.nHasException)
|
||||
{
|
||||
//E bit encountered
|
||||
|
@ -55,16 +54,6 @@ void CVpu::Execute(int32 quota)
|
|||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
|
||||
bool CVpu::MustBreak() const
|
||||
{
|
||||
return m_executor.MustBreak();
|
||||
}
|
||||
|
||||
void CVpu::DisableBreakpointsOnce()
|
||||
{
|
||||
m_executor.DisableBreakpointsOnce();
|
||||
}
|
||||
|
||||
void CVpu::SaveMiniState()
|
||||
{
|
||||
memcpy(m_microMemMiniState, m_microMem, (m_number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE);
|
||||
|
@ -104,7 +93,7 @@ uint32 CVpu::GetVuItopMiniState() const
|
|||
void CVpu::Reset()
|
||||
{
|
||||
m_running = false;
|
||||
m_executor.Reset();
|
||||
m_ctx->m_executor->Reset();
|
||||
m_vif->Reset();
|
||||
}
|
||||
|
||||
|
@ -171,7 +160,7 @@ void CVpu::ExecuteMicroProgram(uint32 nAddress)
|
|||
|
||||
void CVpu::InvalidateMicroProgram()
|
||||
{
|
||||
m_executor.ClearActiveBlocksInRange(0, (m_number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE);
|
||||
m_ctx->m_executor->ClearActiveBlocksInRange(0, (m_number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE);
|
||||
}
|
||||
|
||||
void CVpu::ProcessXgKick(uint32 address)
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "Types.h"
|
||||
#include "../MIPS.h"
|
||||
#include "../Profiler.h"
|
||||
#include "VuExecutor.h"
|
||||
#include "Convertible.h"
|
||||
#include "zip/ZipArchiveWriter.h"
|
||||
#include "zip/ZipArchiveReader.h"
|
||||
|
@ -59,9 +58,6 @@ public:
|
|||
void ProcessXgKick(uint32);
|
||||
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
bool MustBreak() const;
|
||||
void DisableBreakpointsOnce();
|
||||
|
||||
void SaveMiniState();
|
||||
const MIPSSTATE& GetVuMiniState() const;
|
||||
uint8* GetVuMemoryMiniState() const;
|
||||
|
@ -89,7 +85,6 @@ protected:
|
|||
#endif
|
||||
|
||||
unsigned int m_number = 0;
|
||||
CVuExecutor m_executor;
|
||||
bool m_running = false;
|
||||
|
||||
CProfiler::ZoneHandle m_vuProfilerZone = 0;
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
#include <zlib.h>
|
||||
|
||||
CVuExecutor::CVuExecutor(CMIPS& context, uint32 maxAddress)
|
||||
: CMipsExecutor(context, maxAddress)
|
||||
: CGenericMipsExecutor(context, maxAddress)
|
||||
{
|
||||
}
|
||||
|
||||
void CVuExecutor::Reset()
|
||||
{
|
||||
m_cachedBlocks.clear();
|
||||
CMipsExecutor::Reset();
|
||||
CGenericMipsExecutor::Reset();
|
||||
}
|
||||
|
||||
BasicBlockPtr CVuExecutor::BlockFactory(CMIPS& context, uint32 begin, uint32 end)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include "../MipsExecutor.h"
|
||||
#include "../GenericMipsExecutor.h"
|
||||
|
||||
class CVuExecutor : public CMipsExecutor<BlockLookupOneWay>
|
||||
class CVuExecutor : public CGenericMipsExecutor<BlockLookupOneWay>
|
||||
{
|
||||
public:
|
||||
CVuExecutor(CMIPS&, uint32);
|
||||
|
|
|
@ -77,9 +77,8 @@
|
|||
//This is the space needed to preserve at most four arguments in the stack frame (as per MIPS calling convention)
|
||||
#define STACK_FRAME_RESERVE_SIZE 0x10
|
||||
|
||||
CIopBios::CIopBios(CMIPS& cpu, CIopExecutor& cpuExecutor, uint8* ram, uint32 ramSize, uint8* spr)
|
||||
CIopBios::CIopBios(CMIPS& cpu, uint8* ram, uint32 ramSize, uint8* spr)
|
||||
: m_cpu(cpu)
|
||||
, m_cpuExecutor(cpuExecutor)
|
||||
, m_ram(ram)
|
||||
, m_ramSize(ramSize)
|
||||
, m_spr(spr)
|
||||
|
@ -661,7 +660,7 @@ int32 CIopBios::UnloadModule(uint32 loadedModuleId)
|
|||
|
||||
//TODO: Remove module from IOP module list?
|
||||
//TODO: Invalidate MIPS analysis range?
|
||||
m_cpuExecutor.ClearActiveBlocksInRange(loadedModule->start, loadedModule->end);
|
||||
m_cpu.m_executor->ClearActiveBlocksInRange(loadedModule->start, loadedModule->end);
|
||||
|
||||
//TODO: Check return value here.
|
||||
m_sysmem->FreeMemory(loadedModule->start);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "../ELF.h"
|
||||
#include "../OsStructManager.h"
|
||||
#include "../OsVariableWrapper.h"
|
||||
#include "IopExecutor.h"
|
||||
#include "Iop_BiosBase.h"
|
||||
#include "Iop_BiosStructs.h"
|
||||
#include "Iop_SifMan.h"
|
||||
|
@ -126,7 +125,7 @@ public:
|
|||
uint32 reserved[4];
|
||||
};
|
||||
|
||||
CIopBios(CMIPS&, CIopExecutor&, uint8*, uint32, uint8*);
|
||||
CIopBios(CMIPS&, uint8*, uint32, uint8*);
|
||||
virtual ~CIopBios();
|
||||
|
||||
int32 LoadModule(const char*);
|
||||
|
@ -516,7 +515,6 @@ private:
|
|||
#endif
|
||||
|
||||
CMIPS& m_cpu;
|
||||
CIopExecutor& m_cpuExecutor;
|
||||
uint8* m_ram = nullptr;
|
||||
uint32 m_ramSize;
|
||||
uint8* m_spr = nullptr;
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../MipsExecutor.h"
|
||||
|
||||
typedef CMipsExecutor<BlockLookupOneWay> CIopExecutor;
|
|
@ -1,5 +1,6 @@
|
|||
#include "Iop_SubSystem.h"
|
||||
#include "IopBios.h"
|
||||
#include "GenericMipsExecutor.h"
|
||||
#include "../psx/PsxBios.h"
|
||||
#include "../MemoryStateFile.h"
|
||||
#include "../Ps2Const.h"
|
||||
|
@ -18,7 +19,6 @@ using namespace PS2;
|
|||
|
||||
CSubSystem::CSubSystem(bool ps2Mode)
|
||||
: m_cpu(MEMORYMAP_ENDIAN_LSBF)
|
||||
, m_executor(m_cpu, (IOP_RAM_SIZE * 4))
|
||||
, m_ram(new uint8[IOP_RAM_SIZE])
|
||||
, m_scratchPad(new uint8[IOP_SCRATCH_SIZE])
|
||||
, m_spuRam(new uint8[SPU_RAM_SIZE])
|
||||
|
@ -37,13 +37,15 @@ CSubSystem::CSubSystem(bool ps2Mode)
|
|||
{
|
||||
if(ps2Mode)
|
||||
{
|
||||
m_bios = std::make_shared<CIopBios>(m_cpu, m_executor, m_ram, PS2::IOP_RAM_SIZE, m_scratchPad);
|
||||
m_bios = std::make_shared<CIopBios>(m_cpu, m_ram, PS2::IOP_RAM_SIZE, m_scratchPad);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bios = std::make_shared<CPsxBios>(m_cpu, m_ram, PS2::IOP_RAM_SIZE);
|
||||
}
|
||||
|
||||
m_cpu.m_executor = std::make_unique<CGenericMipsExecutor<BlockLookupOneWay>>(m_cpu, (IOP_RAM_SIZE * 4));
|
||||
|
||||
//Read memory map
|
||||
m_cpu.m_pMemoryMap->InsertReadMap((0 * IOP_RAM_SIZE), (0 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x01);
|
||||
m_cpu.m_pMemoryMap->InsertReadMap((1 * IOP_RAM_SIZE), (1 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x02);
|
||||
|
@ -133,8 +135,8 @@ void CSubSystem::Reset()
|
|||
memset(m_ram, 0, IOP_RAM_SIZE);
|
||||
memset(m_scratchPad, 0, IOP_SCRATCH_SIZE);
|
||||
memset(m_spuRam, 0, SPU_RAM_SIZE);
|
||||
m_executor.Reset();
|
||||
m_cpu.Reset();
|
||||
m_cpu.m_executor->Reset();
|
||||
m_cpu.m_analysis->Clear();
|
||||
m_spuCore0.Reset();
|
||||
m_spuCore1.Reset();
|
||||
|
@ -302,7 +304,7 @@ int CSubSystem::ExecuteCpu(int quota)
|
|||
CheckPendingInterrupts();
|
||||
if(!m_cpu.m_State.nHasException)
|
||||
{
|
||||
executed = (quota - m_executor.Execute(quota));
|
||||
executed = (quota - m_cpu.m_executor->Execute(quota));
|
||||
}
|
||||
if(m_cpu.m_State.nHasException)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../MIPS.h"
|
||||
#include "../MA_MIPSIV.h"
|
||||
#include "../COP_SCU.h"
|
||||
#include "IopExecutor.h"
|
||||
#include "Iop_SpuBase.h"
|
||||
#include "Iop_Spu.h"
|
||||
#include "Iop_Spu2.h"
|
||||
|
@ -50,7 +49,6 @@ namespace Iop
|
|||
CMIPS m_cpu;
|
||||
CMA_MIPSIV m_cpuArch;
|
||||
CCOP_SCU m_copScu;
|
||||
CIopExecutor m_executor;
|
||||
BiosBasePtr m_bios;
|
||||
|
||||
private:
|
||||
|
|
|
@ -125,12 +125,12 @@ void CPsfSubSystem::Update(bool singleStep, CSoundHandler* soundHandler)
|
|||
|
||||
bool CPsfSubSystem::MustBreak()
|
||||
{
|
||||
return m_iop.m_executor.MustBreak();
|
||||
return m_iop.m_cpu.m_executor->MustBreak();
|
||||
}
|
||||
|
||||
void CPsfSubSystem::DisableBreakpointsOnce()
|
||||
{
|
||||
m_iop.m_executor.DisableBreakpointsOnce();
|
||||
m_iop.m_cpu.m_executor->DisableBreakpointsOnce();
|
||||
}
|
||||
|
||||
CBiosDebugInfoProvider* CPsfSubSystem::GetBiosDebugInfoProvider()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Psp_PsfSubSystem.h"
|
||||
#include "GenericMipsExecutor.h"
|
||||
#include <thread>
|
||||
|
||||
using namespace Psp;
|
||||
|
@ -12,11 +13,12 @@ CPsfSubSystem::CPsfSubSystem(uint32 ramSize)
|
|||
, m_cpu(MEMORYMAP_ENDIAN_LSBF)
|
||||
, m_copScu(MIPS_REGSIZE_32)
|
||||
, m_copFpu(MIPS_REGSIZE_32)
|
||||
, m_executor(m_cpu, ramSize)
|
||||
, m_spuCore0(m_spuRam, SPURAMSIZE, 0)
|
||||
, m_spuCore1(m_spuRam, SPURAMSIZE, 1)
|
||||
, m_bios(m_cpu, m_ram, ramSize)
|
||||
{
|
||||
m_cpu.m_executor = std::make_unique<CGenericMipsExecutor<BlockLookupTwoWay>>(m_cpu, ramSize);
|
||||
|
||||
//Read memory map
|
||||
m_cpu.m_pMemoryMap->InsertReadMap(0x00000000, m_ramSize, m_ram, 0x01);
|
||||
|
||||
|
@ -44,7 +46,7 @@ void CPsfSubSystem::Reset()
|
|||
{
|
||||
memset(m_ram, 0, m_ramSize);
|
||||
memset(m_spuRam, 0, SPURAMSIZE);
|
||||
m_executor.Reset();
|
||||
m_cpu.m_executor->Reset();
|
||||
m_bios.Reset();
|
||||
m_audioStream.Truncate();
|
||||
|
||||
|
@ -78,7 +80,7 @@ Iop::CSpuBase& CPsfSubSystem::GetSpuCore(unsigned int coreId)
|
|||
|
||||
int CPsfSubSystem::ExecuteCpu(bool singleStep)
|
||||
{
|
||||
int ticks = m_executor.Execute(singleStep ? 1 : 100);
|
||||
int ticks = m_cpu.m_executor->Execute(singleStep ? 1 : 100);
|
||||
if(m_cpu.m_State.nHasException)
|
||||
{
|
||||
m_bios.HandleException();
|
||||
|
@ -132,12 +134,12 @@ void CPsfSubSystem::Update(bool singleStep, CSoundHandler* soundHandler)
|
|||
|
||||
bool CPsfSubSystem::MustBreak()
|
||||
{
|
||||
return m_executor.MustBreak();
|
||||
return m_cpu.m_executor->MustBreak();
|
||||
}
|
||||
|
||||
void CPsfSubSystem::DisableBreakpointsOnce()
|
||||
{
|
||||
m_executor.DisableBreakpointsOnce();
|
||||
m_cpu.m_executor->DisableBreakpointsOnce();
|
||||
}
|
||||
|
||||
CBiosDebugInfoProvider* CPsfSubSystem::GetBiosDebugInfoProvider()
|
||||
|
|
|
@ -6,15 +6,12 @@
|
|||
#include "COP_SCU.h"
|
||||
#include "COP_FPU.h"
|
||||
#include "MIPS.h"
|
||||
#include "MipsExecutor.h"
|
||||
#include "../PsfVmSubSystem.h"
|
||||
#include "Psp_PsfBios.h"
|
||||
#include "MemStream.h"
|
||||
|
||||
namespace Psp
|
||||
{
|
||||
typedef CMipsExecutor<BlockLookupTwoWay> CPspExecutor;
|
||||
|
||||
class CPsfSubSystem : public CPsfVmSubSystem
|
||||
{
|
||||
public:
|
||||
|
@ -51,7 +48,6 @@ namespace Psp
|
|||
int ExecuteCpu(bool);
|
||||
|
||||
CMIPS m_cpu;
|
||||
CPspExecutor m_executor;
|
||||
CMA_ALLEGREX m_cpuArch;
|
||||
CCOP_SCU m_copScu;
|
||||
CCOP_FPU m_copFpu;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue