2020-06-06 22:27:54 -04:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include <regex>
|
|
|
|
#include "GbAssembler.h"
|
|
|
|
#include "LabelManager.h"
|
|
|
|
#include "GameboyDisUtils.h"
|
|
|
|
#include "../Utilities/StringUtilities.h"
|
|
|
|
#include "../Utilities/HexUtilities.h"
|
|
|
|
|
|
|
|
static const std::regex labelRegex = std::regex("^\\s*([@_a-zA-Z][@_a-zA-Z0-9]*)", std::regex_constants::icase);
|
|
|
|
|
|
|
|
GbAssembler::GbAssembler(shared_ptr<LabelManager> labelManager)
|
|
|
|
{
|
|
|
|
_labelManager = labelManager;
|
|
|
|
InitAssembler();
|
|
|
|
}
|
|
|
|
|
2020-06-18 00:58:22 -04:00
|
|
|
GbAssembler::~GbAssembler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-06-06 22:27:54 -04:00
|
|
|
void GbAssembler::InitAssembler()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
for(int i = 0; i < 512; i++) {
|
2020-06-06 22:27:54 -04:00
|
|
|
string op = GameboyDisUtils::GetOpTemplate(i & 0xFF, i >= 256);
|
|
|
|
size_t spaceIndex = op.find(' ');
|
|
|
|
size_t commaIndex = op.find(',');
|
|
|
|
string opName;
|
|
|
|
|
|
|
|
OpCodeEntry entry = {};
|
2021-03-10 11:13:28 -05:00
|
|
|
if(spaceIndex != string::npos) {
|
2020-06-06 22:27:54 -04:00
|
|
|
opName = op.substr(0, spaceIndex);
|
|
|
|
entry.ParamCount = commaIndex != string::npos ? 2 : 1;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
opName = op;
|
|
|
|
entry.ParamCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.OpCode = i < 256 ? i : ((i << 8) | 0xCB);
|
|
|
|
|
|
|
|
std::transform(opName.begin(), opName.end(), opName.begin(), ::tolower);
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_opCodes.find(opName) == _opCodes.end()) {
|
2020-06-06 22:27:54 -04:00
|
|
|
_opCodes[opName] = vector<OpCodeEntry>();
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(entry.ParamCount > 0) {
|
2020-06-06 22:27:54 -04:00
|
|
|
string operands = op.substr(spaceIndex + 1);
|
|
|
|
operands.erase(std::remove_if(operands.begin(), operands.end(), isspace), operands.end());
|
2021-03-10 11:13:28 -05:00
|
|
|
if(entry.ParamCount == 2) {
|
2020-06-06 22:27:54 -04:00
|
|
|
vector<string> operandList = StringUtilities::Split(operands, ',');
|
|
|
|
InitParamEntry(entry.Param1, operandList[0]);
|
|
|
|
InitParamEntry(entry.Param2, operandList[1]);
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(entry.ParamCount == 1) {
|
2020-06-06 22:27:54 -04:00
|
|
|
InitParamEntry(entry.Param1, operands);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_opCodes[opName].push_back(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GbAssembler::InitParamEntry(ParamEntry& entry, string param)
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(param == "a") {
|
2020-06-06 22:27:54 -04:00
|
|
|
entry.Type = ParamType::Short;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(param == "d") {
|
2020-06-06 22:27:54 -04:00
|
|
|
entry.Type = ParamType::Byte;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(param == "e") {
|
2020-06-06 22:27:54 -04:00
|
|
|
entry.Type = ParamType::Short;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(param == "r") {
|
2020-06-06 22:27:54 -04:00
|
|
|
entry.Type = ParamType::RelAddress;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(param == "(a)") {
|
2020-06-06 22:27:54 -04:00
|
|
|
entry.Type = ParamType::Address;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(param == "(c)") {
|
2020-06-06 22:27:54 -04:00
|
|
|
entry.Type = ParamType::HighAddress;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(param == "SP+d") {
|
2020-06-06 22:27:54 -04:00
|
|
|
entry.Type = ParamType::StackOffset;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
std::transform(param.begin(), param.end(), param.begin(), ::tolower);
|
|
|
|
entry.Type = ParamType::Literal;
|
|
|
|
entry.Param = param;
|
|
|
|
}
|
|
|
|
entry.Param = param;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GbAssembler::IsRegisterName(string op)
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
return op == "hl" || op == "af" || op == "bc" || op == "de" || op == "a" || op == "b" || op == "c" || op == "d" || op == "e" || op == "f" || op == "l" || op == "h";
|
2020-06-06 22:27:54 -04:00
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
int GbAssembler::ReadValue(string operand, int min, int max, unordered_map<string, uint16_t>& localLabels, bool firstPass)
|
2020-06-06 22:27:54 -04:00
|
|
|
{
|
|
|
|
int value = 0;
|
2021-03-10 11:13:28 -05:00
|
|
|
switch(operand[0]) {
|
2020-06-06 22:27:54 -04:00
|
|
|
//Hex
|
2021-03-10 11:13:28 -05:00
|
|
|
case '$': value = HexUtilities::FromHex(operand.substr(1)); break;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case '%':
|
|
|
|
//Binary
|
|
|
|
for(size_t i = 1; i < operand.size(); i++) {
|
|
|
|
value <<= 1;
|
|
|
|
value |= operand[i] == '1' ? 1 : 0;
|
2020-12-19 23:30:09 +03:00
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if(std::regex_match(operand, labelRegex)) {
|
|
|
|
if(firstPass) {
|
|
|
|
return 0;
|
|
|
|
} else if(localLabels.find(operand) != localLabels.end()) {
|
|
|
|
value = localLabels.find(operand)->second;
|
|
|
|
} else {
|
|
|
|
int labelAddress = _labelManager->GetLabelRelativeAddress(operand, CpuType::Gameboy);
|
|
|
|
if(labelAddress >= 0) {
|
|
|
|
//Matching label found
|
|
|
|
value = labelAddress;
|
|
|
|
}
|
2020-06-06 22:27:54 -04:00
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
|
|
|
//Decimal
|
|
|
|
for(size_t i = 0; i < operand.size(); i++) {
|
|
|
|
if(operand[i] != '-' && (operand[i] < '0' || operand[i] > '9')) {
|
|
|
|
return -1;
|
|
|
|
}
|
2020-06-06 22:27:54 -04:00
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
try {
|
|
|
|
value = std::stoi(operand);
|
|
|
|
if(value < 0) {
|
|
|
|
value = max + value + 1;
|
|
|
|
}
|
|
|
|
} catch(std::exception&) {
|
|
|
|
return -1;
|
2020-06-06 22:27:54 -04:00
|
|
|
}
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
break;
|
2020-06-06 22:27:54 -04:00
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(value < min || value > max) {
|
2020-06-06 22:27:54 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
bool GbAssembler::IsMatch(ParamEntry& entry, string operand, uint32_t address, unordered_map<string, uint16_t>& localLabels, bool firstPass)
|
2020-06-06 22:27:54 -04:00
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(entry.Type != ParamType::Literal && IsRegisterName(operand)) {
|
2020-06-06 22:27:54 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
switch(entry.Type) {
|
|
|
|
case ParamType::None: return false;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::Literal: {
|
2020-06-06 22:27:54 -04:00
|
|
|
string param = entry.Param;
|
|
|
|
std::transform(param.begin(), param.end(), param.begin(), ::tolower);
|
|
|
|
std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower);
|
|
|
|
return operand == param;
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::Byte:
|
|
|
|
return ReadValue(operand, -128, 0xFF, localLabels, firstPass) >= 0;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::Short:
|
|
|
|
return ReadValue(operand, -32768, 0xFFFF, localLabels, firstPass) >= 0;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::Address:
|
|
|
|
if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') {
|
|
|
|
return ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass) >= 0;
|
|
|
|
}
|
|
|
|
return false;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::HighAddress:
|
|
|
|
if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') {
|
|
|
|
return ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass) >= 0;
|
|
|
|
}
|
|
|
|
return false;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::StackOffset:
|
|
|
|
std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower);
|
|
|
|
if(operand.size() > 3 && operand.substr(0, 3) == "sp+") {
|
|
|
|
return ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass) >= 0;
|
|
|
|
}
|
|
|
|
return false;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::RelAddress: {
|
2020-06-06 22:27:54 -04:00
|
|
|
int value = ReadValue(operand, 0, 0xFFFF, localLabels, firstPass);
|
2021-03-10 11:13:28 -05:00
|
|
|
if(value >= 0) {
|
2020-06-06 22:27:54 -04:00
|
|
|
int offset = (value - (address + 2));
|
|
|
|
return offset >= -128 && offset <= 127;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(firstPass) {
|
2020-06-06 22:27:54 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GbAssembler::PushOp(uint16_t opCode, vector<int16_t>& output, uint32_t& address)
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(opCode < 256) {
|
2020-06-06 22:27:54 -04:00
|
|
|
PushByte((uint8_t)opCode, output, address);
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
PushWord((uint16_t)opCode, output, address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GbAssembler::PushByte(uint8_t operand, vector<int16_t>& output, uint32_t& address)
|
|
|
|
{
|
|
|
|
output.push_back(operand);
|
|
|
|
address++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GbAssembler::PushWord(uint16_t operand, vector<int16_t>& output, uint32_t& address)
|
|
|
|
{
|
|
|
|
output.push_back((uint8_t)operand);
|
|
|
|
output.push_back((operand >> 8));
|
|
|
|
address += 2;
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector<int16_t>& output, uint32_t& address, unordered_map<string, uint16_t>& localLabels, bool firstPass)
|
2020-06-06 22:27:54 -04:00
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
switch(entry.Type) {
|
|
|
|
default:
|
|
|
|
break;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::Byte:
|
|
|
|
PushByte((uint8_t)ReadValue(operand, -128, 255, localLabels, firstPass), output, address);
|
|
|
|
break;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::Short:
|
|
|
|
PushWord((uint16_t)ReadValue(operand, -32768, 65535, localLabels, firstPass), output, address);
|
|
|
|
break;
|
2020-06-06 22:27:54 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
case ParamType::Address:
|
|
|
|
if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') {
|
|
|
|
PushWord((uint16_t)ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass), output, address);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ParamType::HighAddress:
|
|
|
|
if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') {
|
|
|
|
PushByte((uint8_t)ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass), output, address);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ParamType::StackOffset:
|
|
|
|
std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower);
|
|
|
|
if(operand.size() > 3 && operand.substr(0, 3) == "sp+") {
|
|
|
|
PushByte((uint8_t)ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass), output, address);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ParamType::RelAddress: {
|
2020-06-06 22:27:54 -04:00
|
|
|
int value = ReadValue(operand, 0, 0xFFFF, localLabels, firstPass);
|
|
|
|
int offset = (value - (address + 1));
|
|
|
|
PushByte((uint8_t)offset, output, address);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
void GbAssembler::RunPass(vector<int16_t>& output, string code, uint32_t address, int16_t* assembledCode, bool firstPass, unordered_map<string, uint16_t>& localLabels)
|
2020-06-06 22:27:54 -04:00
|
|
|
{
|
|
|
|
unordered_set<string> currentPassLabels;
|
2021-03-10 11:13:28 -05:00
|
|
|
for(string line : StringUtilities::Split(code, '\n')) {
|
2020-06-06 22:27:54 -04:00
|
|
|
//Remove comment
|
|
|
|
size_t commentIndex = line.find(';');
|
2021-03-10 11:13:28 -05:00
|
|
|
if(commentIndex != string::npos) {
|
2020-06-06 22:27:54 -04:00
|
|
|
line = line.substr(0, commentIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check if this is a label definition
|
|
|
|
size_t labelDefIndex = line.find(':');
|
2021-03-10 11:13:28 -05:00
|
|
|
if(labelDefIndex != string::npos) {
|
2020-06-06 22:27:54 -04:00
|
|
|
std::smatch match;
|
|
|
|
string labelName = line.substr(0, labelDefIndex);
|
2021-03-10 11:13:28 -05:00
|
|
|
if(std::regex_search(labelName, match, labelRegex)) {
|
2020-06-06 22:27:54 -04:00
|
|
|
string label = match.str(1);
|
2021-03-10 11:13:28 -05:00
|
|
|
if(firstPass && currentPassLabels.find(label) != currentPassLabels.end()) {
|
2020-06-06 22:27:54 -04:00
|
|
|
output.push_back(AssemblerSpecialCodes::LabelRedefinition);
|
|
|
|
continue;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
localLabels[label] = address;
|
|
|
|
currentPassLabels.emplace(label);
|
|
|
|
line = line.substr(labelDefIndex + 1);
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
output.push_back(AssemblerSpecialCodes::InvalidLabel);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Trim left spaces
|
|
|
|
size_t startIndex = line.find_first_not_of("\t ");
|
2021-03-10 11:13:28 -05:00
|
|
|
if(startIndex > 0 && startIndex != string::npos) {
|
2020-06-06 22:27:54 -04:00
|
|
|
line = line.substr(startIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check if this is a .db statement
|
2021-03-10 11:13:28 -05:00
|
|
|
if(line.size() > 3 && line.substr(0, 3) == ".db") {
|
2020-06-06 22:27:54 -04:00
|
|
|
line = line.substr(3);
|
2021-03-10 11:13:28 -05:00
|
|
|
for(string byte : StringUtilities::Split(line, ' ')) {
|
|
|
|
if(byte.empty()) {
|
2020-06-06 22:27:54 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int value = ReadValue(byte, -128, 255, localLabels, true);
|
2021-03-10 11:13:28 -05:00
|
|
|
if(value >= 0) {
|
2020-06-06 22:27:54 -04:00
|
|
|
PushByte((uint8_t)value, output, address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
output.push_back(AssemblerSpecialCodes::EndOfLine);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Find op code name
|
|
|
|
size_t spaceIndex = line.find(' ');
|
|
|
|
string opName;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(spaceIndex != string::npos) {
|
2020-06-06 22:27:54 -04:00
|
|
|
opName = line.substr(0, spaceIndex);
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
opName = line;
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(opName.empty()) {
|
2020-06-06 22:27:54 -04:00
|
|
|
output.push_back(AssemblerSpecialCodes::EndOfLine);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::transform(opName.begin(), opName.end(), opName.begin(), ::tolower);
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_opCodes.find(opName) == _opCodes.end()) {
|
2020-06-06 22:27:54 -04:00
|
|
|
//No matching opcode found, mark it as invalid
|
|
|
|
output.push_back(AssemblerSpecialCodes::InvalidInstruction);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Find the operands given
|
|
|
|
int paramCount = 0;
|
|
|
|
vector<string> operandList;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(spaceIndex != string::npos) {
|
2020-06-06 22:27:54 -04:00
|
|
|
string operands = line.substr(spaceIndex + 1);
|
|
|
|
operands.erase(std::remove_if(operands.begin(), operands.end(), isspace), operands.end());
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!operands.empty()) {
|
2020-06-06 22:27:54 -04:00
|
|
|
size_t commaIndex = line.find(',');
|
2021-03-10 11:13:28 -05:00
|
|
|
if(commaIndex != string::npos) {
|
2020-06-06 22:27:54 -04:00
|
|
|
paramCount = 2;
|
|
|
|
operandList = StringUtilities::Split(operands, ',');
|
|
|
|
|
|
|
|
bool invalid = operandList.size() > 2;
|
2021-03-10 11:13:28 -05:00
|
|
|
for(string operand : operandList) {
|
|
|
|
if(operand.empty()) {
|
2020-06-06 22:27:54 -04:00
|
|
|
invalid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(invalid) {
|
2020-06-06 22:27:54 -04:00
|
|
|
output.push_back(AssemblerSpecialCodes::InvalidOperands);
|
|
|
|
continue;
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
paramCount = 1;
|
2021-03-10 11:13:28 -05:00
|
|
|
operandList = { operands };
|
2020-06-06 22:27:54 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool matchFound = false;
|
|
|
|
//Find a matching set of opcode + operands
|
2021-03-10 11:13:28 -05:00
|
|
|
for(OpCodeEntry& entry : _opCodes.find(opName)->second) {
|
|
|
|
if(entry.ParamCount == paramCount) {
|
|
|
|
if(paramCount == 0) {
|
2020-06-06 22:27:54 -04:00
|
|
|
PushOp(entry.OpCode, output, address);
|
|
|
|
matchFound = true;
|
|
|
|
break;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(paramCount == 1) {
|
|
|
|
if(IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass)) {
|
2020-06-06 22:27:54 -04:00
|
|
|
PushOp(entry.OpCode, output, address);
|
|
|
|
ProcessOperand(entry.Param1, operandList[0], output, address, localLabels, firstPass);
|
|
|
|
matchFound = true;
|
|
|
|
break;
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(paramCount == 2) {
|
|
|
|
if(IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass) && IsMatch(entry.Param2, operandList[1], address, localLabels, firstPass)) {
|
2020-06-06 22:27:54 -04:00
|
|
|
PushOp(entry.OpCode, output, address);
|
|
|
|
ProcessOperand(entry.Param1, operandList[0], output, address, localLabels, firstPass);
|
|
|
|
ProcessOperand(entry.Param2, operandList[1], output, address, localLabels, firstPass);
|
|
|
|
matchFound = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!matchFound) {
|
2020-06-06 22:27:54 -04:00
|
|
|
output.push_back(AssemblerSpecialCodes::InvalidOperands);
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-06 22:27:54 -04:00
|
|
|
output.push_back(AssemblerSpecialCodes::EndOfLine);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GbAssembler::AssembleCode(string code, uint32_t address, int16_t* assembledCode)
|
|
|
|
{
|
|
|
|
vector<int16_t> output;
|
|
|
|
unordered_map<string, uint16_t> localLabels;
|
|
|
|
|
|
|
|
RunPass(output, code, address, assembledCode, true, localLabels);
|
|
|
|
output.clear();
|
|
|
|
RunPass(output, code, address, assembledCode, false, localLabels);
|
|
|
|
|
|
|
|
memcpy(assembledCode, output.data(), std::min<int>(100000, (int)output.size()) * sizeof(uint16_t));
|
|
|
|
return (uint32_t)output.size();
|
|
|
|
}
|