mirror of
https://github.com/jpd002/Play-.git
synced 2025-05-07 11:13:46 +03:00
330 lines
9.5 KiB
C++
330 lines
9.5 KiB
C++
#include "ArmAssembler.h"
|
|
|
|
CArmAssembler::CArmAssembler(
|
|
const WriteFunctionType& WriteFunction,
|
|
const WriteAtFunctionType& WriteAtFunction,
|
|
const TellFunctionType& TellFunction
|
|
) :
|
|
m_WriteFunction(WriteFunction),
|
|
m_WriteAtFunction(WriteAtFunction),
|
|
m_TellFunction(TellFunction),
|
|
m_nextLabelId(1)
|
|
{
|
|
|
|
}
|
|
|
|
CArmAssembler::~CArmAssembler()
|
|
{
|
|
|
|
}
|
|
|
|
CArmAssembler::LdrAddress CArmAssembler::MakeImmediateLdrAddress(uint32 immediate)
|
|
{
|
|
LdrAddress result;
|
|
memset(&result, 0, sizeof(result));
|
|
assert((immediate & ~0xFFF) == 0);
|
|
result.isImmediate = true;
|
|
result.immediate = static_cast<uint16>(immediate);
|
|
return result;
|
|
}
|
|
|
|
CArmAssembler::ImmediateAluOperand CArmAssembler::MakeImmediateAluOperand(uint8 immediate, uint8 rotateAmount)
|
|
{
|
|
ImmediateAluOperand operand;
|
|
operand.immediate = immediate;
|
|
operand.rotate = rotateAmount;
|
|
return operand;
|
|
}
|
|
|
|
CArmAssembler::RegisterAluOperand CArmAssembler::MakeRegisterAluOperand(CArmAssembler::REGISTER registerId, const AluLdrShift& shift)
|
|
{
|
|
RegisterAluOperand result;
|
|
result.rm = registerId;
|
|
result.shift = *reinterpret_cast<const uint8*>(&shift);
|
|
return result;
|
|
}
|
|
|
|
CArmAssembler::AluLdrShift CArmAssembler::MakeConstantShift(SHIFT shiftType, uint8 amount)
|
|
{
|
|
AluLdrShift result;
|
|
result.typeBit = 0;
|
|
result.type = shiftType;
|
|
result.amount = amount;
|
|
return result;
|
|
}
|
|
|
|
CArmAssembler::AluLdrShift CArmAssembler::MakeVariableShift(SHIFT shiftType, CArmAssembler::REGISTER registerId)
|
|
{
|
|
AluLdrShift result;
|
|
result.typeBit = 1;
|
|
result.type = shiftType;
|
|
result.amount = registerId << 1;
|
|
return result;
|
|
}
|
|
|
|
CArmAssembler::LABEL CArmAssembler::CreateLabel()
|
|
{
|
|
return m_nextLabelId++;
|
|
}
|
|
|
|
void CArmAssembler::MarkLabel(LABEL label)
|
|
{
|
|
m_labels[label] = m_TellFunction();
|
|
}
|
|
|
|
void CArmAssembler::ResolveLabelReferences()
|
|
{
|
|
for(LabelReferenceMapType::iterator labelRef(m_labelReferences.begin());
|
|
m_labelReferences.end() != labelRef; labelRef++)
|
|
{
|
|
LabelMapType::iterator label(m_labels.find(labelRef->first));
|
|
if(label == m_labels.end())
|
|
{
|
|
throw std::runtime_error("Invalid label.");
|
|
}
|
|
size_t referencePos = labelRef->second;
|
|
size_t labelPos = label->second;
|
|
int offset = static_cast<int>(labelPos - referencePos) / 4;
|
|
assert(offset >= 2);
|
|
offset -= 2;
|
|
m_WriteAtFunction(static_cast<unsigned int>(referencePos + 0), static_cast<uint8>(offset >> 0));
|
|
m_WriteAtFunction(static_cast<unsigned int>(referencePos + 1), static_cast<uint8>(offset >> 8));
|
|
m_WriteAtFunction(static_cast<unsigned int>(referencePos + 2), static_cast<uint8>(offset >> 16));
|
|
}
|
|
m_labelReferences.clear();
|
|
}
|
|
|
|
void CArmAssembler::CreateLabelReference(LABEL label)
|
|
{
|
|
LABELREF reference = m_TellFunction();
|
|
m_labelReferences.insert(LabelReferenceMapType::value_type(label, reference));
|
|
}
|
|
|
|
void CArmAssembler::Add(REGISTER rd, REGISTER rn, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rn = rn;
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_ADD;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Add(REGISTER rd, REGISTER rn, const ImmediateAluOperand& operand)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = *reinterpret_cast<const unsigned int*>(&operand);
|
|
instruction.rd = rd;
|
|
instruction.rn = rn;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_ADD;
|
|
instruction.immediate = 1;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::And(REGISTER rd, REGISTER rn, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rn = rn;
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_AND;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::BCc(CONDITION condition, LABEL label)
|
|
{
|
|
CreateLabelReference(label);
|
|
uint32 opcode = (condition << 28) | (0x0A000000);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Blx(REGISTER rn)
|
|
{
|
|
uint32 opcode = 0;
|
|
opcode = (CONDITION_AL << 28) | (0x12FFF30) | (rn);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Cmp(REGISTER rn, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rn = rn;
|
|
instruction.rd = 0;
|
|
instruction.setFlags = 1;
|
|
instruction.opcode = ALU_OPCODE_CMP;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Eor(REGISTER rd, REGISTER rn, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rn = rn;
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_EOR;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Ldr(REGISTER rd, REGISTER rbase, const LdrAddress& address)
|
|
{
|
|
uint32 opcode = 0;
|
|
assert(address.isImmediate);
|
|
opcode = (CONDITION_AL << 28) | (1 << 26) | (1 << 24) | (1 << 23) | (1 << 20) | (static_cast<uint32>(rbase) << 16) | (static_cast<uint32>(rd) << 12) | (static_cast<uint32>(address.immediate));
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Mov(REGISTER rd, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_MOV;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Mov(REGISTER rd, const RegisterAluOperand& operand)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = *reinterpret_cast<const unsigned int*>(&operand);
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_MOV;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Mov(REGISTER rd, const ImmediateAluOperand& operand)
|
|
{
|
|
MovCc(CONDITION_AL, rd, operand);
|
|
}
|
|
|
|
void CArmAssembler::MovCc(CONDITION condition, REGISTER rd, const ImmediateAluOperand& operand)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = *reinterpret_cast<const unsigned int*>(&operand);
|
|
instruction.rd = rd;
|
|
instruction.rn = 0;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_MOV;
|
|
instruction.immediate = 1;
|
|
instruction.condition = condition;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Mvn(REGISTER rd, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_MVN;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Or(REGISTER rd, REGISTER rn, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rn = rn;
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_ORR;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Smull(REGISTER rdLow, REGISTER rdHigh, REGISTER rn, REGISTER rm)
|
|
{
|
|
uint32 opcode = 0;
|
|
opcode = (CONDITION_AL << 28) | (0x06 << 21) | (rdHigh << 16) | (rdLow << 12) | (rm << 8) | (0x9 << 4) | (rn << 0);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Str(REGISTER rd, REGISTER rbase, const LdrAddress& address)
|
|
{
|
|
uint32 opcode = 0;
|
|
assert(address.isImmediate);
|
|
opcode = (CONDITION_AL << 28) | (1 << 26) | (1 << 24) | (1 << 23) | (0 << 20) | (static_cast<uint32>(rbase) << 16) | (static_cast<uint32>(rd) << 12) | (static_cast<uint32>(address.immediate));
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Sub(REGISTER rd, REGISTER rn, REGISTER rm)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = rm;
|
|
instruction.rn = rn;
|
|
instruction.rd = rd;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_SUB;
|
|
instruction.immediate = 0;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Sub(REGISTER rd, REGISTER rn, const ImmediateAluOperand& operand)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = *reinterpret_cast<const unsigned int*>(&operand);
|
|
instruction.rd = rd;
|
|
instruction.rn = rn;
|
|
instruction.setFlags = 0;
|
|
instruction.opcode = ALU_OPCODE_SUB;
|
|
instruction.immediate = 1;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::Teq(REGISTER rn, const ImmediateAluOperand& operand)
|
|
{
|
|
InstructionAlu instruction;
|
|
instruction.operand = *reinterpret_cast<const unsigned int*>(&operand);
|
|
instruction.rd = 0;
|
|
instruction.rn = rn;
|
|
instruction.setFlags = 1;
|
|
instruction.opcode = ALU_OPCODE_TEQ;
|
|
instruction.immediate = 1;
|
|
instruction.condition = CONDITION_AL;
|
|
uint32 opcode = *reinterpret_cast<uint32*>(&instruction);
|
|
WriteWord(opcode);
|
|
}
|
|
|
|
void CArmAssembler::WriteWord(uint32 value)
|
|
{
|
|
m_WriteFunction(reinterpret_cast<uint8*>(&value)[0]);
|
|
m_WriteFunction(reinterpret_cast<uint8*>(&value)[1]);
|
|
m_WriteFunction(reinterpret_cast<uint8*>(&value)[2]);
|
|
m_WriteFunction(reinterpret_cast<uint8*>(&value)[3]);
|
|
}
|