2008-03-24 01:18:20 +00:00
|
|
|
#include "VuExecutor.h"
|
2009-06-06 15:38:03 +00:00
|
|
|
#include "VuBasicBlock.h"
|
2010-11-17 03:59:29 +00:00
|
|
|
#include <zlib.h>
|
2008-03-24 01:18:20 +00:00
|
|
|
|
|
|
|
CVuExecutor::CVuExecutor(CMIPS& context) :
|
|
|
|
CMipsExecutor(context)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CVuExecutor::~CVuExecutor()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-11-17 03:59:29 +00:00
|
|
|
void CVuExecutor::Reset()
|
2009-06-06 15:38:03 +00:00
|
|
|
{
|
2010-11-17 03:59:29 +00:00
|
|
|
m_cachedBlocks.clear();
|
|
|
|
CMipsExecutor::Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
BasicBlockPtr CVuExecutor::BlockFactory(CMIPS& context, uint32 begin, uint32 end)
|
|
|
|
{
|
|
|
|
uint32 blockSize = ((end - begin) + 4) / 4;
|
|
|
|
uint32 blockSizeByte = blockSize * 4;
|
|
|
|
uint32* blockMemory = reinterpret_cast<uint32*>(alloca(blockSizeByte));
|
|
|
|
for(uint32 address = begin; address <= end; address += 8)
|
|
|
|
{
|
|
|
|
uint32 index = (address - begin) / 4;
|
|
|
|
|
|
|
|
uint32 addressLo = address + 0;
|
|
|
|
uint32 addressHi = address + 4;
|
|
|
|
|
|
|
|
uint32 opcodeLo = m_context.m_pMemoryMap->GetInstruction(addressLo);
|
|
|
|
uint32 opcodeHi = m_context.m_pMemoryMap->GetInstruction(addressHi);
|
|
|
|
|
|
|
|
assert((index + 0) < blockSize);
|
|
|
|
blockMemory[index + 0] = opcodeLo;
|
|
|
|
assert((index + 1) < blockSize);
|
|
|
|
blockMemory[index + 1] = opcodeHi;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 checksum = crc32(0, reinterpret_cast<Bytef*>(blockMemory), blockSizeByte);
|
|
|
|
|
|
|
|
std::pair<CachedBlockMap::iterator, CachedBlockMap::iterator> equalRange = m_cachedBlocks.equal_range(checksum);
|
|
|
|
for(; equalRange.first != equalRange.second; ++equalRange.first)
|
|
|
|
{
|
|
|
|
const BasicBlockPtr& basicBlock(equalRange.first->second);
|
|
|
|
if(basicBlock->GetBeginAddress() == begin)
|
|
|
|
{
|
|
|
|
if(basicBlock->GetEndAddress() == end)
|
|
|
|
{
|
|
|
|
return basicBlock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BasicBlockPtr result(new CVuBasicBlock(context, begin, end));
|
|
|
|
m_cachedBlocks.insert(CachedBlockMap::value_type(checksum, result));
|
|
|
|
return result;
|
2009-06-06 15:38:03 +00:00
|
|
|
}
|
|
|
|
|
2008-03-24 01:18:20 +00:00
|
|
|
void CVuExecutor::PartitionFunction(uint32 functionAddress)
|
|
|
|
{
|
2008-06-15 19:55:28 +00:00
|
|
|
const uint32 vuMaxAddress = 0x4000;
|
2008-03-24 01:18:20 +00:00
|
|
|
typedef std::set<uint32> PartitionPointSet;
|
|
|
|
uint32 endAddress = 0;
|
|
|
|
PartitionPointSet partitionPoints;
|
|
|
|
|
|
|
|
//Insert begin point
|
|
|
|
partitionPoints.insert(functionAddress);
|
|
|
|
|
|
|
|
//Find the end
|
|
|
|
for(uint32 address = functionAddress; ; address += 4)
|
|
|
|
{
|
|
|
|
//Probably going too far...
|
|
|
|
if(address >= vuMaxAddress)
|
|
|
|
{
|
|
|
|
endAddress = address;
|
|
|
|
partitionPoints.insert(endAddress);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-06-15 19:55:28 +00:00
|
|
|
uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
|
2008-03-24 01:18:20 +00:00
|
|
|
//If we find the E bit in an upper instruction
|
|
|
|
if((address & 0x04) && (opcode & 0x40000000))
|
|
|
|
{
|
|
|
|
endAddress = address + 8;
|
|
|
|
partitionPoints.insert(endAddress + 4);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Find partition points within the function
|
|
|
|
for(uint32 address = functionAddress; address <= endAddress; address += 4)
|
|
|
|
{
|
2008-06-15 19:55:28 +00:00
|
|
|
uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
|
2011-12-10 20:49:50 +00:00
|
|
|
MIPS_BRANCH_TYPE branchType = m_context.m_pArch->IsInstructionBranch(&m_context, address, opcode);
|
|
|
|
if(branchType == MIPS_BRANCH_NORMAL)
|
2008-03-24 01:18:20 +00:00
|
|
|
{
|
2009-05-05 01:00:58 +00:00
|
|
|
assert((address & 0x07) == 0x00);
|
2008-03-24 01:18:20 +00:00
|
|
|
partitionPoints.insert(address + 0x10);
|
|
|
|
uint32 target = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, address, opcode);
|
|
|
|
if(target > functionAddress && target < endAddress)
|
|
|
|
{
|
2009-05-05 01:00:58 +00:00
|
|
|
assert((target & 0x07) == 0x00);
|
2008-03-24 01:18:20 +00:00
|
|
|
partitionPoints.insert(target);
|
|
|
|
}
|
|
|
|
}
|
2011-12-10 20:49:50 +00:00
|
|
|
|
2008-03-24 01:18:20 +00:00
|
|
|
//Check if there's a block already exising that this address
|
|
|
|
if(address != endAddress)
|
|
|
|
{
|
2010-11-17 03:59:29 +00:00
|
|
|
BasicBlockPtr possibleBlock = FindBlockStartingAt(address);
|
2008-03-24 01:18:20 +00:00
|
|
|
if(possibleBlock != NULL)
|
|
|
|
{
|
|
|
|
assert(possibleBlock->GetEndAddress() <= endAddress);
|
|
|
|
//Add its beginning and end in the partition points
|
|
|
|
partitionPoints.insert(possibleBlock->GetBeginAddress());
|
|
|
|
partitionPoints.insert(possibleBlock->GetEndAddress() + 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-15 19:55:28 +00:00
|
|
|
uint32 currentPoint = MIPS_INVALID_PC;
|
2008-03-24 01:18:20 +00:00
|
|
|
for(PartitionPointSet::const_iterator pointIterator(partitionPoints.begin());
|
|
|
|
pointIterator != partitionPoints.end(); pointIterator++)
|
|
|
|
{
|
2008-06-15 19:55:28 +00:00
|
|
|
if(currentPoint != MIPS_INVALID_PC)
|
2008-03-24 01:18:20 +00:00
|
|
|
{
|
|
|
|
uint32 beginAddress = currentPoint;
|
|
|
|
uint32 endAddress = *pointIterator - 4;
|
|
|
|
//Sanity checks
|
|
|
|
assert((beginAddress & 0x07) == 0x00);
|
|
|
|
assert((endAddress & 0x07) == 0x04);
|
|
|
|
CreateBlock(beginAddress, endAddress);
|
|
|
|
}
|
|
|
|
currentPoint = *pointIterator;
|
|
|
|
}
|
2009-06-06 15:38:03 +00:00
|
|
|
|
|
|
|
//Convenient cutting for debugging purposes
|
|
|
|
//for(uint32 address = functionAddress; address <= endAddress; address += 8)
|
|
|
|
//{
|
|
|
|
// uint32 beginAddress = address;
|
|
|
|
// uint32 endAddress = address + 4;
|
|
|
|
// //Sanity checks
|
|
|
|
// assert((beginAddress & 0x07) == 0x00);
|
|
|
|
// assert((endAddress & 0x07) == 0x04);
|
|
|
|
// CreateBlock(beginAddress, endAddress);
|
|
|
|
//}
|
2008-03-24 01:18:20 +00:00
|
|
|
}
|