Mesen-SX/Core/Assembler.cpp

678 lines
17 KiB
C++
Raw Normal View History

2020-02-11 22:01:06 -05:00
#include "stdafx.h"
#include <regex>
#include <unordered_map>
#include "../Utilities/HexUtilities.h"
#include "../Utilities/StringUtilities.h"
#include "Assembler.h"
#include "Cpu.h"
#include "CpuDisUtils.h"
#include "DisassemblyInfo.h"
#include "LabelManager.h"
2020-12-19 23:30:09 +03:00
static const std::regex instRegex = std::regex(
"^\\s*([a-zA-Z]{3})[\\s]*(#%|#){0,1}([([]{0,1})[\\s]*([$]{0,1})([^\\[\\],)(;:]*)[\\s]*((,[$][0-9a-f]{1,2}|,x\\)|\\),y|,x|,y|,s\\),y|,s|\\)|\\],y|\\]){0,1})\\s*(;*)(.*)",
std::regex_constants::icase);
2020-02-11 22:01:06 -05:00
static const std::regex isCommentOrBlank = std::regex("^\\s*([;]+.*$|\\s*$)", std::regex_constants::icase);
static const std::regex labelRegex = std::regex("^\\s*([@_a-zA-Z][@_a-zA-Z0-9]*):(.*)", std::regex_constants::icase);
2020-12-19 23:30:09 +03:00
static const std::regex byteRegex = std::regex(
"^\\s*[.]db\\s+((\\$[a-fA-F0-9]{1,2}[ ])*)(\\$[a-fA-F0-9]{1,2})+\\s*(;*)(.*)$", std::regex_constants::icase);
2020-02-11 22:01:06 -05:00
2020-12-19 23:30:09 +03:00
void Assembler::ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output,
std::unordered_map<string, uint32_t>& labels, bool firstPass,
std::unordered_map<string, uint32_t>& currentPassLabels)
2020-02-11 22:01:06 -05:00
{
//Remove extra spaces as part of processing
size_t offset = code.find_first_of(',', 0);
2020-12-19 23:30:09 +03:00
if (offset != string::npos)
{
2020-02-11 22:01:06 -05:00
code.erase(std::remove(code.begin() + offset + 1, code.end(), ' '), code.end());
}
offset = code.find_first_of(')', 0);
2020-12-19 23:30:09 +03:00
if (offset != string::npos)
{
2020-02-11 22:01:06 -05:00
code.erase(std::remove(code.begin() + offset + 1, code.end(), ' '), code.end());
}
//Determine if the line is blank, a comment, a label or code
std::smatch match;
2020-12-19 23:30:09 +03:00
if (std::regex_search(code, match, byteRegex))
{
2020-02-11 22:01:06 -05:00
vector<string> bytes = StringUtilities::Split(match.str(1) + match.str(3), ' ');
2020-12-19 23:30:09 +03:00
for (string& byte : bytes)
{
2020-02-11 22:01:06 -05:00
output.push_back((uint8_t)(HexUtilities::FromHex(byte.substr(1))));
instructionAddress++;
}
output.push_back(AssemblerSpecialCodes::EndOfLine);
2020-12-19 23:30:09 +03:00
}
else if (std::regex_search(code, match, labelRegex))
{
2020-02-11 22:01:06 -05:00
string label = match.str(1);
string afterLabel = match.str(2);
2020-12-19 23:30:09 +03:00
if (currentPassLabels.find(match.str(1)) != currentPassLabels.end())
{
2020-02-11 22:01:06 -05:00
output.push_back(AssemblerSpecialCodes::LabelRedefinition);
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
labels[match.str(1)] = instructionAddress;
currentPassLabels[match.str(1)] = instructionAddress;
ProcessLine(afterLabel, instructionAddress, output, labels, firstPass, currentPassLabels);
}
return;
2020-12-19 23:30:09 +03:00
}
else if (std::regex_search(code, match, isCommentOrBlank))
{
2020-02-11 22:01:06 -05:00
output.push_back(AssemblerSpecialCodes::EndOfLine);
return;
2020-12-19 23:30:09 +03:00
}
else if (std::regex_search(code, match, instRegex) && match.size() > 1)
{
2020-02-11 22:01:06 -05:00
LineData lineData;
AssemblerSpecialCodes result = GetLineData(match, lineData, labels, firstPass);
2020-12-19 23:30:09 +03:00
if (result == AssemblerSpecialCodes::OK)
{
2020-02-11 22:01:06 -05:00
AssembleInstruction(lineData, instructionAddress, output, firstPass);
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
output.push_back(result);
}
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
output.push_back(AssemblerSpecialCodes::ParsingError);
}
}
2020-12-19 23:30:09 +03:00
AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineData,
std::unordered_map<string, uint32_t>& labels, bool firstPass)
2020-02-11 22:01:06 -05:00
{
bool isBinary = match.str(2).length() > 1 && match.str(2)[1] == '%'; //Immediate + binary: "#%"
lineData.OpCode = match.str(1);
lineData.IsImmediate = !match.str(2).empty();
lineData.IsHex = !match.str(4).empty();
lineData.HasComment = !match.str(8).empty();
lineData.OperandSuffix = match.str(6);
lineData.HasOpeningParenthesis = match.str(3) == "(";
lineData.HasOpeningBracket = match.str(3) == "[";
2020-12-19 23:30:09 +03:00
std::transform(lineData.OperandSuffix.begin(), lineData.OperandSuffix.end(), lineData.OperandSuffix.begin(),
::toupper);
2020-02-11 22:01:06 -05:00
std::transform(lineData.OpCode.begin(), lineData.OpCode.end(), lineData.OpCode.begin(), ::toupper);
bool foundSpace = false;
2020-12-19 23:30:09 +03:00
for (char c : match.str(5))
{
if (c != ' ' && c != '\t')
{
if (foundSpace)
{
2020-02-11 22:01:06 -05:00
//can't have spaces in operands (except at the very end)
return AssemblerSpecialCodes::InvalidSpaces;
2020-12-19 23:30:09 +03:00
}
else if (lineData.IsHex && !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')))
{
2020-02-11 22:01:06 -05:00
//invalid hex
return AssemblerSpecialCodes::InvalidHex;
2020-12-19 23:30:09 +03:00
}
else if (isBinary && c != '0' && c != '1')
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::InvalidBinaryValue;
}
lineData.Operand.push_back(c);
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
foundSpace = true;
}
}
2020-12-19 23:30:09 +03:00
if (isBinary)
{
2020-02-11 22:01:06 -05:00
//Convert the binary value to hex
2020-12-19 23:30:09 +03:00
if (lineData.Operand.size() == 0)
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::MissingOperand;
2020-12-19 23:30:09 +03:00
}
else if (lineData.Operand.size() <= 8)
{
2020-02-11 22:01:06 -05:00
lineData.IsHex = true;
int value = 0;
2020-12-19 23:30:09 +03:00
for (size_t i = 0; i < lineData.Operand.size(); i++)
{
2020-02-11 22:01:06 -05:00
value <<= 1;
value |= lineData.Operand[i] == '1' ? 1 : 0;
}
lineData.Operand = HexUtilities::ToHex(value, false);
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::OperandOutOfRange;
}
}
2020-12-19 23:30:09 +03:00
if (!lineData.HasComment && !match.str(9).empty())
{
2020-02-11 22:01:06 -05:00
//something is trailing at the end of the line, and it's not a comment
return AssemblerSpecialCodes::TrailingText;
}
2020-12-19 23:30:09 +03:00
if (!lineData.IsHex)
{
2020-02-11 22:01:06 -05:00
bool allNumeric = true;
2020-12-19 23:30:09 +03:00
for (size_t i = 0; i < lineData.Operand.size(); i++)
{
if (lineData.Operand[i] == '-' && i == 0 && lineData.Operand.size() > 1)
{
2020-02-11 22:01:06 -05:00
//First char is a minus sign, and more characters follow, continue
continue;
}
2020-12-19 23:30:09 +03:00
if ((lineData.Operand[i] < '0' || lineData.Operand[i] > '9'))
{
2020-02-11 22:01:06 -05:00
allNumeric = false;
break;
}
}
2020-12-19 23:30:09 +03:00
if (allNumeric && !lineData.Operand.empty())
{
2020-02-11 22:01:06 -05:00
//Operand is not empty, and it only contains decimal values
lineData.IsDecimal = true;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
lineData.IsDecimal = false;
}
}
return GetAddrModeAndOperandSize(lineData, labels, firstPass);
}
2020-12-19 23:30:09 +03:00
AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData& lineData,
std::unordered_map<string, uint32_t>& labels, bool firstPass)
2020-02-11 22:01:06 -05:00
{
int opSize = 0;
bool invalid = false;
string operand = lineData.Operand;
2020-12-19 23:30:09 +03:00
if (lineData.IsHex)
{
if (operand.size() == 0)
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::MissingOperand;
2020-12-19 23:30:09 +03:00
}
else if (operand.size() <= 2)
{
2020-02-11 22:01:06 -05:00
opSize = 1;
2020-12-19 23:30:09 +03:00
}
else if (operand.size() <= 4)
{
2020-02-11 22:01:06 -05:00
opSize = 2;
2020-12-19 23:30:09 +03:00
}
else if (operand.size() <= 6)
{
2020-02-11 22:01:06 -05:00
opSize = 3;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::OperandOutOfRange;
}
2020-12-19 23:30:09 +03:00
}
else if (lineData.IsDecimal)
{
2020-02-11 22:01:06 -05:00
int value = std::stoi(operand.c_str());
2020-12-19 23:30:09 +03:00
if (value < -0x800000)
{
2020-02-11 22:01:06 -05:00
//< -2^23 is invalid
return AssemblerSpecialCodes::OperandOutOfRange;
2020-12-19 23:30:09 +03:00
}
else if (value < -0x8000)
{
2020-02-11 22:01:06 -05:00
opSize = 3;
2020-12-19 23:30:09 +03:00
}
else if (value < -0x80)
{
2020-02-11 22:01:06 -05:00
opSize = 2;
2020-12-19 23:30:09 +03:00
}
else if (value <= 0xFF)
{
2020-02-11 22:01:06 -05:00
opSize = 1;
2020-12-19 23:30:09 +03:00
}
else if (value <= 0xFFFF)
{
2020-02-11 22:01:06 -05:00
opSize = 2;
2020-12-19 23:30:09 +03:00
}
else if (value <= 0xFFFFFF)
{
2020-02-11 22:01:06 -05:00
opSize = 3;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
//>= 2^23 is invalid
return AssemblerSpecialCodes::OperandOutOfRange;
}
2020-12-19 23:30:09 +03:00
}
else if (!operand.empty())
{
2020-02-11 22:01:06 -05:00
//Check if the operand is a known label
auto findResult = labels.find(operand);
2020-12-19 23:30:09 +03:00
if (findResult != labels.end())
{
2020-02-11 22:01:06 -05:00
lineData.Operand = HexUtilities::ToHex((uint16_t)findResult->second);
lineData.IsHex = true;
opSize = 2;
2020-12-19 23:30:09 +03:00
}
else if (operand.size() == 1 && (operand[0] == 'A' || operand[0] == 'a') && lineData.OperandSuffix.empty() && !
lineData.IsHex && !lineData.IsImmediate && !lineData.HasOpeningParenthesis && !lineData.HasOpeningBracket)
{
2020-02-11 22:01:06 -05:00
//Allow optional "A" after AddrMode == Accumulator instructions
lineData.Mode = AddrMode::Acc;
opSize = 0;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
int32_t addr = _labelManager->GetLabelRelativeAddress(operand);
2020-12-19 23:30:09 +03:00
if (addr > 0xFFFF)
{
2020-02-11 22:01:06 -05:00
lineData.Operand = HexUtilities::ToHex24(addr);
lineData.IsHex = true;
opSize = 3;
2020-12-19 23:30:09 +03:00
}
else if (addr > 0xFF)
{
2020-02-11 22:01:06 -05:00
lineData.Operand = HexUtilities::ToHex((uint16_t)addr);
lineData.IsHex = true;
opSize = 2;
2020-12-19 23:30:09 +03:00
}
else if (addr >= 0)
{
2020-02-11 22:01:06 -05:00
lineData.Operand = HexUtilities::ToHex((uint8_t)addr);
lineData.IsHex = true;
opSize = 1;
2020-12-19 23:30:09 +03:00
}
else
{
if (firstPass)
{
2020-02-11 22:01:06 -05:00
//First pass, we couldn't find a matching label, so it might be defined later on
//Pretend it exists for now
_needSecondPass = true;
lineData.Operand = "FFFF";
lineData.IsHex = true;
opSize = 2;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::UnknownLabel;
}
}
}
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
//No operand
opSize = 0;
}
2020-12-19 23:30:09 +03:00
if (lineData.Mode == AddrMode::Imp)
{
if (lineData.OperandSuffix.substr(0, 2) == ",$")
{
2020-02-11 22:01:06 -05:00
//Used by MVP, MVN
opSize = 2;
lineData.Mode = AddrMode::BlkMov;
uint8_t dest = HexUtilities::FromHex(lineData.OperandSuffix.substr(2));
lineData.Operand += HexUtilities::ToHex(dest);
2020-12-19 23:30:09 +03:00
}
else if (lineData.IsImmediate)
{
if (lineData.HasOpeningParenthesis || lineData.HasOpeningBracket || opSize == 0)
{
2020-02-11 22:01:06 -05:00
invalid = true;
2020-12-19 23:30:09 +03:00
}
else if (opSize >= 3)
{
2020-02-11 22:01:06 -05:00
invalid = true;
}
lineData.Mode = opSize == 2 ? AddrMode::Imm16 : AddrMode::Imm8; //or Rel
2020-12-19 23:30:09 +03:00
}
else if (lineData.HasOpeningBracket)
{
if (lineData.OperandSuffix == "]")
{
switch (opSize)
{
case 1: lineData.Mode = AddrMode::DirIndLng;
break;
case 2: lineData.Mode = AddrMode::AbsIndLng;
break;
default: invalid = true;
break;
2020-02-11 22:01:06 -05:00
}
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSuffix == "],Y")
{
if (opSize == 1)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::DirIndLngIdxY;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
invalid = true;
}
}
2020-12-19 23:30:09 +03:00
}
else if (lineData.HasOpeningParenthesis)
{
if (lineData.OperandSuffix == ")")
{
2020-02-11 22:01:06 -05:00
lineData.Mode = opSize == 1 ? AddrMode::DirInd : AddrMode::AbsInd;
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSuffix == ",X)")
{
2020-02-11 22:01:06 -05:00
lineData.Mode = opSize == 1 ? AddrMode::DirIdxIndX : AddrMode::AbsIdxXInd;
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSuffix == "),Y")
{
if (opSize == 1)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::DirIndIdxY;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::OperandOutOfRange;
}
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSuffix == ",S),Y")
{
if (opSize == 1)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::StkRelIndIdxY;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::OperandOutOfRange;
}
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
invalid = true;
}
2020-12-19 23:30:09 +03:00
}
else
{
if (lineData.OperandSuffix == ",X")
{
if (opSize == 3)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::AbsLngIdxX;
2020-12-19 23:30:09 +03:00
}
else if (opSize == 2)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::AbsIdxX;
2020-12-19 23:30:09 +03:00
}
else if (opSize == 1)
{
2020-02-11 22:01:06 -05:00
//Sometimes zero page addressing is not available, even if the operand is in the zero page
lineData.Mode = AddrMode::DirIdxX;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
invalid = true;
}
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSuffix == ",Y")
{
if (opSize == 2)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::AbsIdxY;
2020-12-19 23:30:09 +03:00
}
else if (opSize == 1)
{
2020-02-11 22:01:06 -05:00
//Sometimes zero page addressing is not available, even if the operand is in the zero page
lineData.Mode = AddrMode::DirIdxY;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
invalid = true;
}
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSuffix == ",S")
{
if (opSize == 1)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::StkRel;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
return AssemblerSpecialCodes::OperandOutOfRange;
}
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSuffix.empty())
{
if (opSize == 0)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::Imp; //or Acc
2020-12-19 23:30:09 +03:00
}
else if (opSize == 3)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::AbsLng;
2020-12-19 23:30:09 +03:00
}
else if (opSize == 2)
{
2020-02-11 22:01:06 -05:00
lineData.Mode = AddrMode::Abs;
2020-12-19 23:30:09 +03:00
}
else if (opSize == 1)
{
2020-02-11 22:01:06 -05:00
//Sometimes zero page addressing is not available, even if the operand is in the zero page
lineData.Mode = AddrMode::Dir;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
invalid = true;
}
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
invalid = true;
}
}
}
/*if(lineData.Mode == AddrMode::None) {
invalid = true;
}*/
lineData.OperandSize = opSize;
return invalid ? AssemblerSpecialCodes::ParsingError : AssemblerSpecialCodes::OK;
}
bool Assembler::IsOpModeAvailable(string& opCode, AddrMode mode)
{
return _availableModesByOpName[opCode].find((int)mode) != _availableModesByOpName[opCode].end();
}
2020-12-19 23:30:09 +03:00
void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector<int16_t>& output,
bool firstPass)
2020-02-11 22:01:06 -05:00
{
bool foundMatch = false;
2020-12-19 23:30:09 +03:00
for (int i = 0; i < 256; i++)
{
2020-02-11 22:01:06 -05:00
AddrMode opMode = CpuDisUtils::OpMode[i];
2020-12-19 23:30:09 +03:00
if (lineData.OpCode == CpuDisUtils::OpName[i])
{
2020-02-11 22:01:06 -05:00
bool modeMatch = opMode == lineData.Mode;
2020-12-19 23:30:09 +03:00
if (!modeMatch)
{
if (lineData.Mode == AddrMode::Imp && (opMode == AddrMode::Acc || opMode == AddrMode::Stk))
{
2020-02-11 22:01:06 -05:00
modeMatch = true;
2020-12-19 23:30:09 +03:00
}
else if (lineData.Mode == AddrMode::Imm8 && opMode == AddrMode::Sig8)
{
2020-02-11 22:01:06 -05:00
modeMatch = true;
2020-12-19 23:30:09 +03:00
}
else if ((lineData.Mode == AddrMode::Imm8 || lineData.Mode == AddrMode::Imm16) && (opMode == AddrMode::ImmX
|| opMode == AddrMode::ImmM))
{
2020-02-11 22:01:06 -05:00
modeMatch = true;
2020-12-19 23:30:09 +03:00
}
else if ((opMode == AddrMode::Rel || opMode == AddrMode::RelLng) && (lineData.Mode == AddrMode::AbsLng ||
lineData.Mode == AddrMode::Abs || lineData.Mode == AddrMode::Dir))
{
2020-02-11 22:01:06 -05:00
bool lngBranch = opMode == AddrMode::RelLng;
modeMatch = true;
//Convert "absolute" jump to a relative jump
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
2020-12-19 23:30:09 +03:00
if (lineData.Mode == AddrMode::Abs)
{
2020-02-11 22:01:06 -05:00
value |= (instructionAddress & 0xFF0000);
}
int32_t addressGap;
2020-12-19 23:30:09 +03:00
if (lineData.Mode == AddrMode::Dir)
{
2020-02-11 22:01:06 -05:00
addressGap = (int8_t)value;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
addressGap = value - (instructionAddress + (lngBranch ? 3 : 2));
}
2020-12-19 23:30:09 +03:00
if (addressGap > (lngBranch ? 32767 : 127) || addressGap < (lngBranch ? -32768 : -128))
{
2020-02-11 22:01:06 -05:00
//Gap too long, can't jump that far
2020-12-19 23:30:09 +03:00
if (!firstPass)
{
2020-02-11 22:01:06 -05:00
//Pretend this is ok on first pass, we're just trying to find all labels
output.push_back(AssemblerSpecialCodes::OutOfRangeJump);
return;
}
}
//Update data to match relative jump
lineData.OperandSize = lngBranch ? 2 : 1;
lineData.IsHex = true;
2020-12-19 23:30:09 +03:00
lineData.Operand = lngBranch
? HexUtilities::ToHex((uint16_t)addressGap)
: HexUtilities::ToHex((uint8_t)addressGap);
2020-02-11 22:01:06 -05:00
}
}
2020-12-19 23:30:09 +03:00
if (modeMatch)
{
2020-02-11 22:01:06 -05:00
output.push_back(i);
instructionAddress += (lineData.OperandSize + 1);
2020-12-19 23:30:09 +03:00
if (lineData.OperandSize == 1)
{
2020-02-11 22:01:06 -05:00
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
output.push_back(value & 0xFF);
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSize == 2)
{
2020-02-11 22:01:06 -05:00
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
output.push_back(value & 0xFF);
output.push_back((value >> 8) & 0xFF);
2020-12-19 23:30:09 +03:00
}
else if (lineData.OperandSize == 3)
{
2020-02-11 22:01:06 -05:00
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
output.push_back(value & 0xFF);
output.push_back((value >> 8) & 0xFF);
output.push_back((value >> 16) & 0xFF);
}
foundMatch = true;
break;
}
}
}
2020-12-19 23:30:09 +03:00
if (!foundMatch)
{
2020-02-11 22:01:06 -05:00
output.push_back(AssemblerSpecialCodes::InvalidInstruction);
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
output.push_back(AssemblerSpecialCodes::EndOfLine);
}
}
Assembler::Assembler(shared_ptr<LabelManager> labelManager)
{
_labelManager = labelManager;
}
2020-06-06 22:27:54 -04:00
Assembler::~Assembler()
{
}
2020-02-11 22:01:06 -05:00
uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode)
{
2020-12-19 23:30:09 +03:00
for (uint8_t i = 0; i < 255; i++)
{
if (_availableModesByOpName.find(CpuDisUtils::OpName[i]) == _availableModesByOpName.end())
{
2020-02-11 22:01:06 -05:00
_availableModesByOpName[CpuDisUtils::OpName[i]] = std::unordered_set<int>();
}
_availableModesByOpName[CpuDisUtils::OpName[i]].emplace((int)CpuDisUtils::OpMode[i]);
}
std::unordered_map<string, uint32_t> temporaryLabels;
std::unordered_map<string, uint32_t> currentPassLabels;
size_t i = 0;
vector<int16_t> output;
output.reserve(1000);
uint32_t originalStartAddr = startAddress;
vector<string> codeLines;
codeLines.reserve(100);
2020-12-19 23:30:09 +03:00
while (i < code.size())
{
2020-02-11 22:01:06 -05:00
size_t offset = code.find_first_of('\n', i);
string line;
2020-12-19 23:30:09 +03:00
if (offset != string::npos)
{
2020-02-11 22:01:06 -05:00
line = code.substr(i, offset - i);
i = offset + 1;
2020-12-19 23:30:09 +03:00
}
else
{
2020-02-11 22:01:06 -05:00
line = code.substr(i);
i = code.size();
}
codeLines.push_back(line);
}
//Make 2 passes - first one to find all labels, second to assemble
_needSecondPass = false;
2020-12-19 23:30:09 +03:00
for (string& line : codeLines)
{
2020-02-11 22:01:06 -05:00
ProcessLine(line, startAddress, output, temporaryLabels, true, currentPassLabels);
}
2020-12-19 23:30:09 +03:00
if (_needSecondPass)
{
2020-02-11 22:01:06 -05:00
currentPassLabels.clear();
output.clear();
startAddress = originalStartAddr;
2020-12-19 23:30:09 +03:00
for (string& line : codeLines)
{
2020-02-11 22:01:06 -05:00
ProcessLine(line, startAddress, output, temporaryLabels, false, currentPassLabels);
}
}
memcpy(assembledCode, output.data(), std::min<int>(100000, (int)output.size()) * sizeof(uint16_t));
2020-02-11 22:01:06 -05:00
return (uint32_t)output.size();
}