#include "Assembler.hpp" #include #include #include #include #include #include #include "../tools/GlobalData.hpp" #include "../hardware/VirtualHardDrive.hpp" #include "../hardware/CPUExtensions.hpp" #include "../tools/Utils.hpp" namespace dragon { namespace code { std::vector IncludePreprocessor::loadEntryFile(const ostd::String& filePath) { m_guards.clear(); m_lines.clear(); m_directory = ""; m_lines = __load_file(filePath); if (m_lines.size() == 0) return { }; //TODO: Error if (filePath.contains("/")) m_directory = filePath.new_substr(0, filePath.lastIndexOf("/") + 1); if (!__can_file_be_included(m_lines)) return { }; //TODO: Error if (!__include_loop()) return { }; //TODO: Error std::vector newLines; for (auto& line : m_lines) { line.trim(); if (line != "") newLines.push_back(line); } m_lines.clear(); m_lines = newLines; return m_lines; } bool IncludePreprocessor::__can_file_be_included(std::vector& lines) { ostd::String guard_name = ""; for (auto& line : lines) { ostd::String lineEdit = line.new_trim(); if (lineEdit.new_toLower().startsWith("@guard ")) { guard_name = lineEdit.new_substr(7).trim(); line = ""; break; } } if (guard_name == "") return true; for (auto& guard : m_guards) { if (guard == guard_name) return false; } m_guards.push_back(guard_name); return true; } bool IncludePreprocessor::__include_loop(void) { std::vector lines = m_lines; bool included = false; do { included = false; uint32_t i = 0; for ( ; i < lines.size(); i++) { ostd::String line = lines[i]; line.trim(); if (line.new_toLower().startsWith("@include") && line.len() > 8) { line.substr(8).trim(); if (!line.startsWith("<") || !line.endsWith(">")) return false; line.substr(1, line.len() - 1).trim(); auto file_lines = __load_file(m_directory + line); if (file_lines.size() == 0) return false; lines.erase(lines.begin() + i); if (__can_file_be_included(file_lines)) { lines.insert(lines.begin() + i, file_lines.begin(), file_lines.end()); included = true; } break; } } } while(included); m_lines = lines; return true; } std::vector IncludePreprocessor::__load_file(const ostd::String& filePath) { ostd::TextFileBuffer file(filePath); if (!file.exists()) return { }; //TODO: Error ostd::String source = file.rawContent(); return ostd::String(source.replaceAll("\t", " ")).tokenize("\n").getRawData(); } int32_t Assembler::Application::loadArguments(int argc, char** argv) { if (argc < 2) { out.fg(ostd::ConsoleColors::Red).p("Error: too few arguments.").nl(); out.fg(ostd::ConsoleColors::Red).p("Use the --help option for more info.").reset().nl(); return RETURN_VAL_TOO_FEW_ARGUMENTS; } else { args.source_file_path = argv[1]; if (args.source_file_path == "--help") { print_application_help(); return RETURN_VAL_CLOSE_PROGRAM; } for (int32_t i = 2; i < argc; i++) { ostd::String edit(argv[i]); if (edit == "-o") { if (i == argc - 1) return RETURN_VAL_MISSING_PARAM; i++; args.dest_file_path = argv[i]; } else if (edit == "--save-disassembly") { if (i == argc - 1) return RETURN_VAL_MISSING_PARAM; i++; args.disassembly_file_path = argv[i]; args.save_disassembly = true; } else if (edit == "--help") { print_application_help(); return RETURN_VAL_CLOSE_PROGRAM; } else if (edit == "--extmov") args.cpu_extensions.push_back("extmov"); else if (edit == "--extalu") args.cpu_extensions.push_back("extalu"); else if (edit == "--verbose") args.verbose = true; else if (edit == "--save-exports") args.save_exports = true; } } return RETURN_VAL_EXIT_SUCCESS; } void Assembler::Application::print_application_help(void) { int32_t commandLength = 46; out.nl().fg(ostd::ConsoleColors::Yellow).p("List of available parameters:").reset().nl(); ostd::String tmpCommand = "--save-disassembly "; tmpCommand.addRightPadding(commandLength); out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Saves debug information in the destination directory.").reset().nl(); tmpCommand = "--verbose"; tmpCommand.addRightPadding(commandLength); out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Shows more information about the assembled program.").reset().nl(); tmpCommand = "-o "; tmpCommand.addRightPadding(commandLength); out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to specify the output binary file.").reset().nl(); tmpCommand = "--save-exports"; tmpCommand.addRightPadding(commandLength); out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Used to save any specified exports in the code.").reset().nl(); tmpCommand = "--extmov"; tmpCommand.addRightPadding(commandLength); out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Enables mnemonics for the CPU extension.").reset().nl(); tmpCommand = "--extalu"; tmpCommand.addRightPadding(commandLength); out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Enables mnemonics for the CPU extension.").reset().nl(); tmpCommand = "--help"; tmpCommand.addRightPadding(commandLength); out.fg(ostd::ConsoleColors::Blue).p(tmpCommand).fg(ostd::ConsoleColors::Green).p("Displays this help message.").reset().nl(); out.nl().fg(ostd::ConsoleColors::Magenta).p("Usage: ./dasm -o [...options...]").reset().nl(); out.nl(); } ostd::ByteStream Assembler::assembleFromFile(ostd::String fileName) { m_rawSource = ""; m_code.clear(); m_lines.clear(); m_rawDataSection.clear(); m_rawCodeSection.clear(); m_symbolTable.clear(); m_labelTable.clear(); m_disassembly.clear(); m_structDefs.clear(); m_fixedSize = 0; m_fixedFillValue = 0x00; m_loadAddress = 0x0000; m_currentDataAddr = 0x0000; m_dataSize = 0x0000; m_lines = IncludePreprocessor::loadEntryFile(fileName); if (m_lines.size() == 0) return { }; //TODO: Error removeComments(); parseExportSpecs(); replaceGroupDefines(); replaceDefines(); parseStructures(); replaceDefines(); parseSections(); parseStructInstances(); parseDataSection(); parseCodeSection(); replaceLabelRefs(); combineDataAndCode(); processExports(); m_programSize = m_code.size(); if (m_fixedSize > 0 && m_code.size() > m_fixedSize) std::cout << "Warning: Fixed size specified but exceeded: (" << (int)m_code.size() << "/" << (int)m_fixedSize << " bytes)\n"; else if (m_fixedSize > 0 && m_code.size() < m_fixedSize) { for (int16_t i = m_code.size(); i < m_fixedSize; i++) m_code.push_back(m_fixedFillValue); } return m_code; } ostd::ByteStream Assembler::assembleToFile(ostd::String sourceFileName, ostd::String binaryFileName) { assembleFromFile(sourceFileName); if (m_code.size() == 0) return { }; ostd::Utils::saveByteStreamToFile(m_code, binaryFileName); return m_code; } ostd::ByteStream Assembler::assembleToVirtualDisk(ostd::String fileName, hw::VirtualHardDrive& vhdd, uint32_t address) { assembleFromFile(fileName); if (m_code.size() == 0) return { }; for (int32_t i = 0; i < m_code.size(); i++) vhdd.write(address + i, m_code[i]); return m_code; } bool Assembler::saveDisassemblyToFile(ostd::String fileName) { if (m_code.size() == 0 || m_disassembly.size() == 0) return false; ostd::String header_string = "{ DRAGON_DEBUG_DISASSEMBLY }"; uint64_t da_size = 0; da_size += (header_string.len() + 1) * ostd::tTypeSize::BYTE; da_size += m_disassembly.size() * ostd::tTypeSize::DWORD; //Addresses da_size += m_disassembly.size() * ostd::tTypeSize::WORD; //Data Size da_size += m_disassembly.size() * ostd::tTypeSize::BYTE; //Null Termination for (auto& da : m_disassembly) da_size += da.code.len() * ostd::tTypeSize::BYTE; //Code Strings ostd::serial::SerialIO serializer(da_size, ostd::serial::SerialIO::tEndianness::BigEndian); ostd::StreamIndex stream_addr = 0; serializer.w_String(stream_addr, header_string); stream_addr += (header_string.len() + 1) * ostd::tTypeSize::BYTE; for (auto& da : m_disassembly) { serializer.w_DWord(stream_addr, da.addr); stream_addr += ostd::tTypeSize::DWORD; serializer.w_Word(stream_addr, (int16_t)da.size); stream_addr += ostd::tTypeSize::WORD; serializer.w_String(stream_addr, da.code); stream_addr += (da.code.len() + 1) * ostd::tTypeSize::BYTE; } return serializer.saveToFile(fileName); } void Assembler::removeComments(void) { std::vector newLines; ostd::String lineEdit; for (auto& line : m_lines) { lineEdit = line; lineEdit.trim(); if (lineEdit.startsWith("##")) continue; if (lineEdit.contains("##")) { lineEdit = lineEdit.substr(0, lineEdit.indexOf("##")); lineEdit.trim(); } newLines.push_back(lineEdit); } m_lines.clear(); m_lines = newLines; } void Assembler::parseExportSpecs(void) { auto exportAlreadyExists = [](const std::unordered_map& exports, const ostd::String& name) -> bool { return exports.count(name) > 0; }; std::vector newLines; ostd::String lineEdit = ""; ostd::String tmpLineEdit = ""; for (auto& line : m_lines) { lineEdit = line; lineEdit.trim(); tmpLineEdit = lineEdit; if (tmpLineEdit.toLower().startsWith("@export ")) { lineEdit = lineEdit.substr(8); lineEdit.trim(); if (!lineEdit.contains(" ")) { std::cout << "Invalid @export directive: " << line << "\n"; return; } ostd::String export_name = lineEdit.new_substr(0, lineEdit.indexOf(" ")).trim(); ostd::String export_file = lineEdit.new_substr(lineEdit.indexOf(" ") + 1).trim(); if (export_name == "" || export_file == "") { std::cout << "Invalid @export directive (null value(s)): " << line << "\n"; return; } if (exportAlreadyExists(m_exportSpecifications, export_name)) { std::cout << "An export specification with this name already exists: " << line << "\n"; return; } m_exportSpecifications[export_name] = { export_file, {} }; continue; } newLines.push_back(lineEdit); } m_lines.clear(); m_lines = newLines; } void Assembler::processExports(void) { for (auto& exp : m_exportSpecifications) { for (auto& def : exp.second.content) { if (def.name.startsWith("##")) { def.value.replaceAll("\\n", "\n"); continue; } if (def.value.startsWith("{") && def.value.endsWith("}")) { def.value.substr(1, def.value.len() - 1).trim(); int16_t val = (int16_t)ostd::Utils::solveIntegerExpression(def.value); def.value = ostd::Utils::getHexStr(val, true, 2); } } } if (!saveExports) return; for (auto& exp : m_exportSpecifications) { ostd::String fileContent = "## -- \n## -- This file is automatically generated by the DragonAssembler (version "; fileContent.add(VERSION_STR).add(")\n"); fileContent.add("## -- Please do not modify this file in any way."); fileContent.add("\n## -- \n\n"); fileContent.add("@guard __AUTO_GEN_GUARD_").add(exp.first.new_toUpper()).add("_DSS__\n\n"); std::filesystem::path filePath(exp.second.fileName.cpp_str()); uint32_t define_fixed_length = 96; for (auto& def : exp.second.content) { if (def.name.startsWith("##")) { fileContent.add(def.name).add(def.value).add("\n"); continue; } fileContent.add("@define "); fileContent.add(def.name.new_addRightPadding(define_fixed_length)).add(" ").add(def.value).add("\n"); } std::ofstream outFile(filePath, std::ofstream::out | std::ofstream::trunc); if (!std::filesystem::exists(filePath)) { std::cout << "Invalid export specification file: " << filePath << "\n"; continue; } outFile << fileContent.cpp_str(); outFile.close(); } } void Assembler::replaceDefines(void) { auto listContainsDefine = [](const std::vector& list, const ostd::String& name) -> bool { for (auto& def : list) { if (def.name == name) return true; } return false; }; auto exportExists = [](const std::unordered_map& exports, const ostd::String& name) -> bool { return exports.count(name) > 0; }; std::vector defines; std::vector newLines; ostd::String lineEdit; ostd::String tmpLineEdit; for (auto& line : m_lines) { lineEdit = line; lineEdit.trim(); tmpLineEdit = lineEdit; ostd::String export_name = ""; if (tmpLineEdit.toLower().startsWith("@export_comment ")) { lineEdit.substr(16).trim(); if (!lineEdit.startsWith("/") || !lineEdit.contains(" ")) { std::cout << "Invalid @export_comment directive: export specification not found: " << line << "\n"; return; } export_name = lineEdit.new_substr(1, lineEdit.indexOf(" ")).trim(); lineEdit.substr(lineEdit.indexOf(" ") + 1).trim(); if (!lineEdit.startsWith("\"") || !lineEdit.endsWith("\"")) { std::cout << "Invalid @export_comment directive: comment not found: " << line << "\n"; return; } lineEdit.substr(1, lineEdit.len() - 1); if (!exportExists(m_exportSpecifications, export_name)) { std::cout << "Invalid export specification: " << line << "\n"; return; } m_exportSpecifications[export_name].content.push_back({ "## -- ", lineEdit }); continue; } else if (tmpLineEdit.toLower().startsWith("@define ")) { lineEdit.substr(8).trim(); if (lineEdit.startsWith("/")) { if (!lineEdit.contains(" ")) { std::cout << "Invalid export definition for group: " << line << "\n"; return; } export_name = lineEdit.new_substr(1, lineEdit.indexOf(" ")).trim(); lineEdit.substr(lineEdit.indexOf(" ") + 1).trim(); } if (!lineEdit.contains(" ")) { std::cout << "Invalid @define directive: " << line << "\n"; return; } ostd::String define_name = lineEdit.new_substr(0, lineEdit.indexOf(" ")).trim(); ostd::String define_value = lineEdit.new_substr(lineEdit.indexOf(" ") + 1).trim(); if (listContainsDefine(defines, define_name)) { std::cout << "Redefinition of @define value: " << line << "\n"; return; } defines.push_back({ define_name, define_value }); if (export_name != "") { if (!exportExists(m_exportSpecifications, export_name)) { std::cout << "Invalid export specification: " << line << "\n"; return; } m_exportSpecifications[export_name].content.push_back({ define_name, define_value }); } continue; } newLines.push_back(lineEdit); } for (auto& line : newLines) { ostd::String lineEdit(line); for (int32_t i = defines.size() - 1; i >= 0; i--) lineEdit.replaceAll(defines[i].name, defines[i].value.new_trim()); line = lineEdit; } for (auto& exp : m_exportSpecifications) { for (auto& def : exp.second.content) { for (int32_t i = defines.size() - 1; i >= 0; i--) def.value.replaceAll(defines[i].name, defines[i].value.new_trim()); } } m_lines.clear(); m_lines = newLines; } void Assembler::replaceGroupDefines(void) { std::vector newLines; ostd::String lineEdit; bool in_group = false; ostd::String group_name = ""; ostd::String export_name = ""; for (auto& line : m_lines) { lineEdit = line; lineEdit.trim(); if (lineEdit.new_toLower().startsWith("@group ")) { if (in_group) { std::cout << "Nested define groups not allowed: " << line << "\n"; return; } lineEdit.substr(6).trim(); if (lineEdit.startsWith("/")) { if (!lineEdit.contains(" ")) { std::cout << "Invalid export definition for group: " << line << "\n"; return; } export_name = lineEdit.new_substr(0, lineEdit.indexOf(" ")).trim(); lineEdit.substr(lineEdit.indexOf(" ") + 1).trim(); } if (lineEdit == "") { std::cout << "Group name cannot be empty: " << line << "\n"; return; } group_name = lineEdit; in_group = true; continue; } else if (in_group && lineEdit.new_toLower() == "@end") { if (!in_group) { std::cout << "Missing group declaration for @end directive: " << line << "\n"; return; } export_name = ""; in_group = false; continue; } if (!in_group) { newLines.push_back(lineEdit); continue; } if (!lineEdit.contains(" ")) { std::cout << "Invalid definition inside group: " << line << "\n"; return; } ostd::String newLine = "@define " + export_name + " "; newLine.add(group_name).add(".").add(lineEdit); newLines.push_back(newLine); } m_lines.clear(); m_lines = newLines; } void Assembler::parseSections(void) { constexpr uint8_t DATA_SECTION = 0x01; constexpr uint8_t CODE_SECTION = 0x02; uint8_t currentSection = 0x00; for (auto& line : m_lines) { ostd::String lineEdit(line); if (lineEdit.startsWith(".data")) currentSection = DATA_SECTION; else if (lineEdit.startsWith(".code")) currentSection = CODE_SECTION; else if (lineEdit.startsWith(".fixed ")) { if (lineEdit.len() < 8) { //TODO: Error std::cout << "Invalid .fixed value: " << lineEdit << "\n"; return; } lineEdit = lineEdit.substr(7); lineEdit.trim(); if (!lineEdit.contains(",")) { //TODO: Error std::cout << "Invalid .fixed value: " << lineEdit << "\n"; return; } ostd::String fixedSizeEdit = lineEdit.new_substr(0, lineEdit.indexOf(",")); fixedSizeEdit.trim(); lineEdit = lineEdit.substr(lineEdit.indexOf(",") + 1); lineEdit.trim(); if (!lineEdit.isNumeric()) { //TODO: Error std::cout << "Invalid .fixed size value: " << lineEdit << "\n"; return; } m_fixedFillValue = lineEdit.toInt(); if (!fixedSizeEdit.isNumeric()) { //TODO: Error std::cout << "Invalid .fixed fill value: " << lineEdit << "\n"; return; } m_fixedSize = fixedSizeEdit.toInt(); continue; } else if (lineEdit.startsWith(".load ")) { if (lineEdit.len() < 7) { //TODO: Error std::cout << "Invalid .load value: " << lineEdit << "\n"; return; } lineEdit = lineEdit.substr(6); lineEdit.trim(); if (!lineEdit.isNumeric()) { //TODO: Error std::cout << "Invalid .load value: " << lineEdit << "\n"; return; } m_loadAddress = lineEdit.toInt(); m_currentDataAddr = m_loadAddress + 3; continue; } else if (lineEdit.startsWith(".")) { //TODO: Error std::cout << "Invalid section: " << lineEdit << "\n"; return; } else { if (currentSection == DATA_SECTION) m_rawDataSection.push_back(line); else if (currentSection == CODE_SECTION) m_rawCodeSection.push_back(line); else { //TODO: Error std::cout << "Invalid section: " << lineEdit << "\n"; return; } } } } void Assembler::parseStructInstances(void) { std::vector newLines; ostd::String lineEdit; bool in_group = false; ostd::String group_name = ""; for (auto& line : m_rawDataSection) { lineEdit = line; lineEdit.trim(); if (!lineEdit.startsWith("$") || lineEdit.indexOf(" ") < 2) { std::cout << "Invalid data entry: " << lineEdit << "\n"; return; } ostd::String symbolName = lineEdit.new_substr(0, lineEdit.indexOf(" ")); symbolName.trim(); lineEdit.substr(lineEdit.indexOf(" ") + 1); lineEdit.trim(); ostd::String initialization_data = ""; bool has_init_data = false; if (lineEdit.startsWith("<") && lineEdit.contains("=")) { initialization_data = lineEdit.new_substr(lineEdit.indexOf("=") + 1).trim(); if (initialization_data.startsWith("(") && initialization_data.endsWith(")")) { initialization_data.substr(1, initialization_data.len() - 1).trim(); has_init_data = initialization_data != ""; } else { std::cout << "Invalid initialization data: " << lineEdit << "\n"; return; } lineEdit.substr(0, lineEdit.indexOf("=")).trim(); } if (lineEdit.startsWith("<") && lineEdit.endsWith(">") && lineEdit.len() > 2) { lineEdit = lineEdit.substr(1, lineEdit.len() - 1); std::vector init_data; if (has_init_data) { auto tokens = initialization_data.tokenize(","); while (tokens.hasNext()) { ostd::String tok = tokens.next(); if (!tok.isNumeric()) { std::cout << "Invalid initialization data: " << lineEdit << "\n"; return; } init_data.push_back((uint8_t)tok.toInt()); } } tStructDefinition struct_def; bool found = false; for (auto& _struct : m_structDefs) { if (_struct.name == lineEdit) { struct_def = _struct; found = true; break; } } if (!found) { std::cout << "Unknown Structure name: " << lineEdit << "\n"; return; } if (has_init_data && struct_def.size != init_data.size()) { std::cout << "Structure size must match initialization data size: " << lineEdit << "\n"; return; } int32_t data_index = 0; newLines.push_back("!" + symbolName); for (auto& member : struct_def.members) { ostd::String newLine = symbolName; newLine.add(".").add(member.name).add(" "); for (int32_t i = 0; i < member.data.size(); i++, data_index++) { if (has_init_data) newLine.add(ostd::Utils::getHexStr(init_data[data_index], true, 2)); else newLine.add(ostd::Utils::getHexStr(member.data[i], true, 2)); newLine.add(","); } newLine.substr(0, newLine.len() - 1); newLines.push_back(newLine); } continue; } newLines.push_back(line); } m_rawDataSection.clear(); m_rawDataSection = newLines; } void Assembler::parseStructures(void) { std::vector newLines; ostd::String lineEdit; bool in_struct = false; ostd::String struct_name = ""; tStructDefinition struct_def; int32_t member_index = 0; for (auto& line : m_lines) { lineEdit = line; lineEdit.trim(); if (lineEdit.new_toLower().startsWith("@struct ")) { if (in_struct) { std::cout << "Nested structs not allowed: " << line << "\n"; return; } lineEdit.substr(7).trim(); if (lineEdit == "") { std::cout << "Struct name cannot be empty: " << line << "\n"; return; } struct_name = lineEdit; struct_def.members.clear(); struct_def.name = struct_name; member_index = 0; in_struct = true; continue; } else if (in_struct && lineEdit.new_toLower() == "@end") { if (!in_struct) { std::cout << "Missing struct declaration for @end directive: " << line << "\n"; return; } struct_def.size = 0; for (auto& data : struct_def.members) struct_def.size += data.data.size(); std::sort(struct_def.members.begin(), struct_def.members.end()); m_structDefs.push_back(struct_def); ostd::String size_def = "@define "; size_def.add(struct_def.name).add(".").add("SIZE").add(" "); size_def.add(ostd::Utils::getHexStr(struct_def.size, true, 2)); newLines.push_back(size_def); in_struct = false; continue; } if (!in_struct) { newLines.push_back(lineEdit); continue; } if (!lineEdit.contains(":")) { std::cout << "Invalid definition inside struct. Size specification missing: " << line << "\n"; return; } ostd::String member_name = lineEdit.new_substr(0, lineEdit.indexOf(":")).trim(); ostd::String member_data = ""; lineEdit.substr(lineEdit.indexOf(":") + 1).trim(); if (member_name.contains(" ")) { std::cout << "Invalid definition inside struct. Member name cannot contain spaces: " << line << "\n"; return; } if (lineEdit.contains(">")) { member_data = lineEdit.new_substr(lineEdit.indexOf(">") + 1).trim(); lineEdit.substr(0, lineEdit.indexOf(">")).trim(); } if (!lineEdit.isNumeric()) { std::cout << "Invalid definition inside struct. Member size must be numeric: " << line << "\n"; return; } int32_t bytes = lineEdit.toInt(); if (bytes < 1) { std::cout << "Invalid definition inside struct. Member must be at least 1 Byte: " << line << "\n"; return; } tStructMember member; member.position = member_index++; member.name = member_name; if (member_data == "") { for (int32_t i = 0; i < bytes; i++) member.data.push_back(0x00); } else { auto tokens = member_data.tokenize(","); if (tokens.count() == 1) { ostd::String tok = tokens.next(); if (tok.isNumeric()) { uint8_t data = (uint8_t)tok.toInt(); for (int32_t i = 0; i < bytes; i++) member.data.push_back(data); } else { std::cout << "Invalid definition inside struct. Member data must be numeric: " << line << "\n"; return; } } else { if (tokens.count() != bytes) { std::cout << "Invalid definition inside struct. Member data count and size mismatch: " << line << "\n"; return; } while (tokens.hasNext()) { ostd::String tok = tokens.next(); if (tok.isNumeric()) { uint8_t data = (uint8_t)tok.toInt(); member.data.push_back(data); } else { std::cout << "Invalid definition inside struct. Member data must be numeric: " << line << "\n"; return; } } } } struct_def.members.push_back(member); } m_lines.clear(); m_lines = newLines; // for (auto& str : m_structDefs) // { // std::cout << str.name << "\n"; // for(auto& d : str.memberData) // { // std::cout << " " << d.first << " "; // for (auto& b : d.second) // std::cout << ostd::Utils::getHexStr(b) << " "; // } // std::cout << "\n"; // } // std::cin.get(); } void Assembler::parseDataSection(void) { // for (auto& line : m_rawDataSection) // std::cout << line << "\n"; for (auto& line : m_rawDataSection) { ostd::String lineEdit(line); tSymbol symbol; if (lineEdit.startsWith("!")) { if (lineEdit.contains(" ")) { std::cout << "Invalid phantom data entry: " << lineEdit << "\n"; continue; } lineEdit.substr(1).trim(); symbol.bytes.clear(); symbol.address = m_currentDataAddr; m_symbolTable[lineEdit] = symbol; continue; } if (!lineEdit.startsWith("$") || lineEdit.indexOf(" ") < 2) { std::cout << "Invalid data entry: " << lineEdit << "\n"; continue; } ostd::String symbolName = lineEdit.new_substr(0, lineEdit.indexOf(" ")); symbolName.trim(); lineEdit.substr(lineEdit.indexOf(" ") + 1); lineEdit.trim(); if (lineEdit.isNumeric()) { // union valueSplit { // uint16_t value; // uint8_t bytes[2]; // } split; // split.value = lineEdit.toInt(); // symbol.bytes.push_back(split.bytes[0]); // symbol.bytes.push_back(split.bytes[1]); // symbol.address = m_currentDataAddr; // m_currentDataAddr += 2; int8_t value = lineEdit.toInt(); symbol.bytes.push_back(value); symbol.address = m_currentDataAddr; m_currentDataAddr += 1; m_symbolTable[symbolName] = symbol; continue; } else if (lineEdit.startsWith("\"") && lineEdit.endsWith("\"") && lineEdit.len() > 2) { lineEdit = lineEdit.substr(1, lineEdit.len() - 1); for (auto c : lineEdit) symbol.bytes.push_back((uint8_t)c); symbol.bytes.push_back((uint8_t)0); //NULL Termination symbol.address = m_currentDataAddr; m_currentDataAddr += symbol.bytes.size(); m_symbolTable[symbolName] = symbol; continue; } else if (lineEdit.contains(",")) { auto tokens = lineEdit.tokenize(","); if (tokens.count() < 2) { std::cout << "Invalid data entry: " << lineEdit << "\n"; return; } for (auto& token : tokens) { lineEdit = token; if (!lineEdit.isNumeric()) { std::cout << "Invalid byte in data entry: " << lineEdit << "\n"; return; } symbol.bytes.push_back((uint8_t)lineEdit.toInt()); } symbol.address = m_currentDataAddr; m_currentDataAddr += symbol.bytes.size(); m_symbolTable[symbolName] = symbol; continue; } else { std::cout << "Invalid data entry: " << lineEdit << "\n"; continue; } } for (auto& symbol : m_symbolTable) { m_dataSize += symbol.second.bytes.size(); } } void Assembler::parseCodeSection(void) { for (auto& line : m_rawCodeSection) { ostd::String lineEdit(line); uint32_t commaCount = lineEdit.count(","); uint32_t spaceCount = lineEdit.count(" "); if (lineEdit.endsWith(":") && commaCount == 0 && spaceCount == 0) //Labels { lineEdit = lineEdit.substr(0, lineEdit.len() - 1); lineEdit.trim(); m_labelTable["$" + lineEdit] = { { }, 0x0000 }; continue; } } tDisassemblyLine _disassembly_line; for (auto& line : m_rawCodeSection) { ostd::String lineEdit(line); uint32_t commaCount = lineEdit.count(","); uint32_t spaceCount = lineEdit.count(" "); if (lineEdit.endsWith(":") && commaCount == 0 && spaceCount == 0) //Labels { // _disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3; // _disassembly_line.code = lineEdit; // m_disassembly.push_back(_disassembly_line); lineEdit = lineEdit.substr(0, lineEdit.len() - 1); lineEdit.trim(); m_labelTable["$" + lineEdit].address = m_dataSize + m_loadAddress + m_code.size() + 3; continue; } else if (lineEdit.startsWith("%low ")) //Low level code injection { _disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3; lineEdit.substr(4).trim(); auto tok = lineEdit.tokenize(); for (auto& token : tok) { if (!token.isNumeric()) { std::cout << "Invalid code in .low directive. Must be numeric byte strem, space-separated: " << line << "\n"; return; } m_code.push_back((int8_t)token.toInt()); } _disassembly_line.code = lineEdit; _disassembly_line.code.add(" (%low)"); m_disassembly.push_back(_disassembly_line); continue; } else if (commaCount == 0 && spaceCount <= 0) //0 Operands { _disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3; ostd::String _tmp_edit(lineEdit); if (_tmp_edit.toLower().trim().startsWith("debug_")) parseDebugOperands(lineEdit); else parse0Operand(lineEdit); _disassembly_line.code = lineEdit; m_disassembly.push_back(_disassembly_line); continue; } else if (commaCount == 0) //1 Operands { _disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3; lineEdit = replaceSymbols(lineEdit); parse1Operand(lineEdit); _disassembly_line.code = lineEdit; m_disassembly.push_back(_disassembly_line); continue; } else if (commaCount == 1) //2 Operands { _disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3; lineEdit = replaceSymbols(lineEdit); parse2Operand(lineEdit); _disassembly_line.code = lineEdit; m_disassembly.push_back(_disassembly_line); continue; } else if (commaCount == 2) // 3 Operands { _disassembly_line.addr = m_dataSize + m_loadAddress + m_code.size() + 3; lineEdit = replaceSymbols(lineEdit); parse3Operand(lineEdit); _disassembly_line.code = lineEdit; m_disassembly.push_back(_disassembly_line); continue; } else { std::cout << "Invalid syntax: " << lineEdit << "\n"; return; } } } void Assembler::parse0Operand(ostd::String line) { if (ostd::String(line).toLower().startsWith("nop")) { m_code.push_back(data::OpCodes::NoOp); return; } else if (ostd::String(line).toLower().startsWith("ret")) { m_code.push_back(data::OpCodes::Ret); return; } else if (ostd::String(line).toLower().startsWith("rti")) { m_code.push_back(data::OpCodes::RetInt); return; } else if (ostd::String(line).toLower().startsWith("hlt")) { m_code.push_back(data::OpCodes::Halt); return; } } void Assembler::parseDebugOperands(ostd::String line) { if (ostd::String(line).toLower().startsWith("debug_break")) { m_code.push_back(data::OpCodes::DEBUG_Break); return; } } void Assembler::parse1Operand(ostd::String line) { ostd::String lineEdit(line); ostd::String instEdit(lineEdit.new_substr(0, lineEdit.indexOf(" "))); instEdit.trim().toLower(); ostd::String opEdit(lineEdit.new_substr(lineEdit.indexOf(" ") + 1)); opEdit.trim(); int16_t word = 0x0000; if (instEdit == "inc") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back(data::OpCodes::IncReg); m_code.push_back((uint8_t)word); return; } else if (instEdit == "dec") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back(data::OpCodes::DecReg); m_code.push_back((uint8_t)word); return; } else if (instEdit == "arg") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back(data::OpCodes::ArgReg); m_code.push_back((uint8_t)word); return; } else if (instEdit == "push") { eOperandType opType = parseOperand(opEdit, word); if (opType == eOperandType::Immediate || opType == eOperandType::Label) { m_code.push_back(data::OpCodes::PushImm); m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); } else if (opType == eOperandType::Register) { m_code.push_back(data::OpCodes::PushReg); m_code.push_back((uint8_t)word); } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register or Immediate required\n"; exit(0); } return; } else if (instEdit == "pop") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back(data::OpCodes::PopReg); m_code.push_back((uint8_t)word); return; } else if (instEdit == "call") { m_code.push_back(0x00); eOperandType opType = parseOperand(opEdit, word); if (opType == eOperandType::Immediate || opType == eOperandType::Label) { m_code[m_code.size() - 1] = data::OpCodes::CallImm; m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); } else if (opType == eOperandType::Register) { m_code[m_code.size() - 1] = data::OpCodes::CallReg; m_code.push_back((uint8_t)word); } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register or Immediate (Label) required\n"; exit(0); } return; } else if (instEdit == "not") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back(data::OpCodes::NotReg); m_code.push_back((uint8_t)word); return; } else if (instEdit == "neg") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back(data::OpCodes::NegReg); m_code.push_back((uint8_t)word); return; } else if (instEdit == "negb") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back(data::OpCodes::NegByteReg); m_code.push_back((uint8_t)word); return; } else if (instEdit == "jmp") { m_code.push_back(data::OpCodes::Jmp); eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Label && opType != eOperandType::Immediate) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Immediate (or label) required\n"; exit(0); return; } m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); return; } else if (instEdit == "int") { eOperandType opType = parseOperand(opEdit, word); if (opType != eOperandType::Immediate) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Immediate required\n"; exit(0); return; } m_code.push_back(data::OpCodes::Int); m_code.push_back((uint8_t)word); return; } else { std::cout << "Unknown instruction; " << line << " (" << instEdit << ")\n"; exit(0); } } void Assembler::parse2Operand(ostd::String line) { ostd::String lineEdit(line); ostd::String instEdit(lineEdit.new_substr(0, lineEdit.indexOf(" "))); instEdit.trim().toLower(); ostd::String opEdit(lineEdit.new_substr(lineEdit.indexOf(" ") + 1)); opEdit.trim(); int16_t word = 0x0000; auto st = opEdit.tokenize(","); if (STDVEC_CONTAINS(cpuExtensions, "extalu")) { auto st = opEdit.tokenize(","); if (instEdit == "addipu" || instEdit == "subipu" || instEdit == "mulipu" || instEdit == "divipu" || instEdit == "addip" || instEdit == "subip" || instEdit == "mulip" || instEdit == "divip") { m_code.push_back(data::OpCodes::Ext02); m_code.push_back(0x00); eOperandType opType = parseOperand(st.next(), word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back((uint8_t)word); opType = parseOperand(st.next(), word); if (opType == eOperandType::Immediate) { if (instEdit == "addip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::addip_imm_in_reg; else if (instEdit == "subip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::subip_imm_in_reg; else if (instEdit == "mulip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::mulip_imm_in_reg; else if (instEdit == "divip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::divip_imm_in_reg; else if (instEdit == "addipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::addipu_imm_in_reg; else if (instEdit == "subipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::subipu_imm_in_reg; else if (instEdit == "mulipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::mulipu_imm_in_reg; else if (instEdit == "divipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::divipu_imm_in_reg; m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); } else if (opType == eOperandType::Register) { if (instEdit == "addip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::addip_reg_in_reg; else if (instEdit == "subip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::subip_reg_in_reg; else if (instEdit == "mulip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::mulip_reg_in_reg; else if (instEdit == "divip") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::divip_reg_in_reg; else if (instEdit == "addipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::addipu_reg_in_reg; else if (instEdit == "subipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::subipu_reg_in_reg; else if (instEdit == "mulipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::mulipu_reg_in_reg; else if (instEdit == "divipu") m_code[m_code.size() - 2] = hw::cpuext::ExtAlu::OpCodes::divipu_reg_in_reg; m_code.push_back((uint8_t)word); } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Immediate or register required\n"; exit(0); return; } return; } } else if (instEdit == "addipu" || instEdit == "subipu" || instEdit == "mulipu" || instEdit == "divipu" || instEdit == "addip" || instEdit == "subip" || instEdit == "mulip" || instEdit == "divip") { std::cout << "ExtAlu instruction detected, please add '--extalu' flag to dasm.\n"; exit(0); return; } if (instEdit == "mov") { m_code.push_back(0x00); int16_t word1 = 0x0000; int16_t word2 = 0x0000; eOperandType opType1 = parseOperand(st.next(), word1); if (opType1 == eOperandType::Register) { m_code.push_back((uint8_t)word1); eOperandType opType2 = parseOperand(st.next(), word2); switch (opType2) { case eOperandType::Immediate: case eOperandType::Label: m_code[m_code.size() - 2] = data::OpCodes::MovImmReg; m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); break; case eOperandType::Register: m_code[m_code.size() - 2] = data::OpCodes::MovRegReg; m_code.push_back((uint8_t)word2); break; case eOperandType::DerefMemory: m_code[m_code.size() - 2] = data::OpCodes::MovMemReg; m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); break; case eOperandType::DerefRegister: m_code[m_code.size() - 2] = data::OpCodes::MovDerefRegReg; m_code.push_back((uint8_t)word2); return; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::DerefMemory) { m_code.push_back((uint8_t)((word1 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word1 & 0x00FF)); eOperandType opType2 = parseOperand(st.next(), word2); switch (opType2) { case eOperandType::Register: m_code[m_code.size() - 3] = data::OpCodes::MovRegMem; m_code.push_back((uint8_t)word2); break; case eOperandType::DerefRegister: m_code[m_code.size() - 3] = data::OpCodes::MovDerefRegMem; m_code.push_back((uint8_t)word2); break; case eOperandType::Immediate: case eOperandType::Label: m_code[m_code.size() - 3] = data::OpCodes::MovImmMem; m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::DerefRegister) { m_code.push_back((uint8_t)word1); eOperandType opType2 = parseOperand(st.next(), word2); switch (opType2) { case eOperandType::Register: m_code[m_code.size() - 2] = data::OpCodes::MovRegDerefReg; m_code.push_back((uint8_t)word2); break; case eOperandType::DerefMemory: m_code[m_code.size() - 2] = data::OpCodes::MovMemDerefReg; m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); break; case eOperandType::Immediate: case eOperandType::Label: m_code[m_code.size() - 2] = data::OpCodes::MovImmDerefReg; m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); break; case eOperandType::DerefRegister: m_code[m_code.size() - 2] = data::OpCodes::MovDerefRegDerefReg; m_code.push_back((uint8_t)word2); return; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } return; } else if (instEdit == "movb") { m_code.push_back(0x00); int16_t word1 = 0x0000; int16_t word2 = 0x0000; eOperandType opType1 = parseOperand(st.next(), word1); if (opType1 == eOperandType::DerefMemory) { m_code.push_back((uint8_t)((word1 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word1 & 0x00FF)); eOperandType opType2 = parseOperand(st.next(), word2); switch (opType2) { case eOperandType::Immediate: m_code[m_code.size() - 3] = data::OpCodes::MovByteImmMem; m_code.push_back((uint8_t)word2); break; case eOperandType::DerefRegister: m_code[m_code.size() - 3] = data::OpCodes::MovByteDerefRegMem; m_code.push_back((uint8_t)word2); break; case eOperandType::Register: m_code[m_code.size() - 3] = data::OpCodes::MovByteRegMem; m_code.push_back((uint8_t)word2); break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::DerefRegister) { m_code.push_back((uint8_t)word1); eOperandType opType2 = parseOperand(st.next(), word2); switch (opType2) { case eOperandType::Register: m_code[m_code.size() - 2] = data::OpCodes::MovByteRegDerefReg; m_code.push_back((uint8_t)word2); break; case eOperandType::DerefMemory: m_code[m_code.size() - 2] = data::OpCodes::MovByteMemDerefReg; m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); break; case eOperandType::Immediate: m_code[m_code.size() - 2] = data::OpCodes::MovByteImmDerefReg; m_code.push_back((uint8_t)word2); break; case eOperandType::DerefRegister: m_code[m_code.size() - 2] = data::OpCodes::MovByteDerefRegDerefReg; m_code.push_back((uint8_t)word2); return; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::Register) { m_code.push_back((uint8_t)word1); eOperandType opType2 = parseOperand(st.next(), word2); switch (opType2) { case eOperandType::Immediate: m_code[m_code.size() - 2] = data::OpCodes::MovByteImmReg; m_code.push_back((uint8_t)word2); break; case eOperandType::DerefMemory: m_code[m_code.size() - 2] = data::OpCodes::MovByteMemReg; m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); break; case eOperandType::DerefRegister: m_code[m_code.size() - 2] = data::OpCodes::MovByteDerefRegReg; m_code.push_back((uint8_t)word2); return; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } return; } else if (instEdit == "add" || instEdit == "sub" || instEdit == "mul" || instEdit == "div") { m_code.push_back(0x00); eOperandType opType = parseOperand(st.next(), word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } m_code.push_back((uint8_t)word); opType = parseOperand(st.next(), word); if (opType == eOperandType::Immediate) { if (instEdit == "add") m_code[m_code.size() - 2] = data::OpCodes::AddImmReg; else if (instEdit == "sub") m_code[m_code.size() - 2] = data::OpCodes::SubImmReg; else if (instEdit == "mul") m_code[m_code.size() - 2] = data::OpCodes::MulImmReg; else if (instEdit == "div") m_code[m_code.size() - 2] = data::OpCodes::DivImmReg; m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); } else if (opType == eOperandType::Register) { if (instEdit == "add") m_code[m_code.size() - 2] = data::OpCodes::AddRegReg; else if (instEdit == "sub") m_code[m_code.size() - 2] = data::OpCodes::SubRegReg; else if (instEdit == "mul") m_code[m_code.size() - 2] = data::OpCodes::MulRegReg; else if (instEdit == "div") m_code[m_code.size() - 2] = data::OpCodes::DivRegReg; m_code.push_back((uint8_t)word); } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Immediate or register required\n"; exit(0); return; } return; } else if (instEdit == "lsh" || instEdit == "rsh" || instEdit == "and" || instEdit == "or" || instEdit == "xor") { eOperandType opType = parseOperand(st.next(), word); if (opType != eOperandType::Register) { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register required\n"; exit(0); return; } uint8_t regAddr = (uint8_t)word; opType = parseOperand(st.next(), word); if (opType == eOperandType::Immediate) { if (instEdit == "lsh") m_code.push_back(data::OpCodes::LShiftRegImm); else if (instEdit == "rsh") m_code.push_back(data::OpCodes::RShiftRegImm); else if (instEdit == "and") m_code.push_back(data::OpCodes::AndRegImm); else if (instEdit == "or") m_code.push_back(data::OpCodes::OrRegImm); else if (instEdit == "xor") m_code.push_back(data::OpCodes::XorRegImm); m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); m_code.push_back((uint8_t)regAddr); } else if (opType == eOperandType::Register) { if (instEdit == "lsh") m_code.push_back(data::OpCodes::LShiftRegReg); else if (instEdit == "rsh") m_code.push_back(data::OpCodes::RShiftRegReg); else if (instEdit == "and") m_code.push_back(data::OpCodes::AndRegReg); else if (instEdit == "or") m_code.push_back(data::OpCodes::OrRegReg); else if (instEdit == "xor") m_code.push_back(data::OpCodes::XorRegReg); m_code.push_back((uint8_t)word); m_code.push_back((uint8_t)regAddr); } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Register or immediate required\n"; exit(0); return; } return; } else if (instEdit == "jne" || instEdit == "jeq" || instEdit == "jgr" || instEdit == "jls" || instEdit == "jge" || instEdit == "jle") { m_code.push_back(0x00); eOperandType opType = parseOperand(st.next(), word); if (opType != eOperandType::Immediate && opType != eOperandType::Label) { std::cout << (int)opType << "\n"; std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> Immediate (or label) required\n"; exit(0); return; } m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); opType = parseOperand(st.next(), word); if (opType == eOperandType::Immediate) { if (instEdit == "jeq") m_code[m_code.size() - 3] = data::OpCodes::JmpEqImm; else if (instEdit == "jne") m_code[m_code.size() - 3] = data::OpCodes::JmpNotEqImm; else if (instEdit == "jgr") m_code[m_code.size() - 3] = data::OpCodes::JmpGrImm; else if (instEdit == "jls") m_code[m_code.size() - 3] = data::OpCodes::JmpLessImm; else if (instEdit == "jge") m_code[m_code.size() - 3] = data::OpCodes::JmpGeImm; else if (instEdit == "jle") m_code[m_code.size() - 3] = data::OpCodes::JmpLeImm; m_code.push_back((uint8_t)((word & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word & 0x00FF)); } else if (opType == eOperandType::Register) { if (instEdit == "jeq") m_code[m_code.size() - 3] = data::OpCodes::JmpEqReg; else if (instEdit == "jne") m_code[m_code.size() - 3] = data::OpCodes::JmpNotEqReg; else if (instEdit == "jgr") m_code[m_code.size() - 3] = data::OpCodes::JmpGrReg; else if (instEdit == "jls") m_code[m_code.size() - 3] = data::OpCodes::JmpLessReg; else if (instEdit == "jge") m_code[m_code.size() - 3] = data::OpCodes::JmpGeReg; else if (instEdit == "jle") m_code[m_code.size() - 3] = data::OpCodes::JmpLeReg; m_code.push_back((uint8_t)word); } else { std::cout << "Invalid operand type: " << line << " (" << opEdit << ") -> Immediate or register required\n"; exit(0); return; } return; } else { std::cout << "Unknown instruction: " << line << " (" << instEdit << ")\n"; exit(0); } } void Assembler::parse3Operand(ostd::String line) { ostd::String lineEdit(line); ostd::String instEdit(lineEdit.new_substr(0, lineEdit.indexOf(" "))); instEdit.trim().toLower(); ostd::String opEdit(lineEdit.new_substr(lineEdit.indexOf(" ") + 1)); opEdit.trim(); if (STDVEC_CONTAINS(cpuExtensions, "extmov")) { uint16_t code_offset = 1; int16_t word1 = 0x0000; int16_t word2 = 0x0000; int16_t word3 = 0x0000; auto st = opEdit.tokenize(","); if (instEdit == "omov") { m_code.push_back(data::OpCodes::Ext01); m_code.push_back(0x00); if (st.count() != 3) { std::cout << "Invalid operand number; " << line << "3 -> 3 required\n"; exit(0); return; } eOperandType opType1 = parseOperand(st.next(), word1); if (opType1 == eOperandType::DerefRegister) { m_code.push_back((uint8_t)word1); code_offset++; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::Immediate: case eOperandType::Label: m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); code_offset += 2; break; case eOperandType::DerefRegister: m_code.push_back((uint8_t)word2); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { if (opType2 == eOperandType::Immediate || opType2 == eOperandType::Label) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wimm_in_dreg_immoffw; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_in_dreg_immoffw; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { if (opType2 == eOperandType::Immediate || opType2 == eOperandType::Label) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wimm_in_dreg_immoffb; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_in_dreg_immoffb; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: if (opType2 == eOperandType::Immediate || opType2 == eOperandType::Label) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wimm_in_dreg_regoff; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_in_dreg_regoff; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::DerefMemory) { m_code.push_back((uint8_t)((word1 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word1 & 0x00FF)); code_offset += 2; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::Immediate: case eOperandType::Label: m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); code_offset += 2; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wimm_in_mem_immoffw; m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wimm_in_mem_immoffb; m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wimm_in_mem_regoff; m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> DerefRegister or Pointer required\n"; exit(0); return; } } else if (instEdit == "omovb") { m_code.push_back(data::OpCodes::Ext01); m_code.push_back(0x00); if (st.count() != 3) { std::cout << "Invalid operand number; " << line << "3 -> 3 required\n"; exit(0); return; } eOperandType opType1 = parseOperand(st.next(), word1); if (opType1 == eOperandType::DerefRegister) { m_code.push_back((uint8_t)word1); code_offset++; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::Immediate: case eOperandType::Label: m_code.push_back((uint8_t)word2); code_offset += 1; break; case eOperandType::DerefRegister: m_code.push_back((uint8_t)word2); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { if (opType2 == eOperandType::Immediate || opType2 == eOperandType::Label) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bimm_in_dreg_immoffw; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_in_dreg_immoffw; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { if (opType2 == eOperandType::Immediate || opType2 == eOperandType::Label) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bimm_in_dreg_immoffb; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_in_dreg_immoffb; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: if (opType2 == eOperandType::Immediate || opType2 == eOperandType::Label) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bimm_in_dreg_regoff; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_in_dreg_regoff; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::DerefMemory) { m_code.push_back((uint8_t)((word1 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word1 & 0x00FF)); code_offset += 2; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::Immediate: case eOperandType::Label: m_code.push_back((uint8_t)word2); code_offset += 1; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bimm_in_mem_immoffw; m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bimm_in_mem_immoffb; m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bimm_in_mem_regoff; m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> DerefRegister or Pointer required\n"; exit(0); return; } } else if (instEdit == "movo") { m_code.push_back(data::OpCodes::Ext01); m_code.push_back(0x00); if (st.count() != 3) { std::cout << "Invalid operand number; " << line << "3 -> 3 required\n"; exit(0); return; } eOperandType opType1 = parseOperand(st.next(), word1); if (opType1 == eOperandType::Register) { m_code.push_back((uint8_t)word1); code_offset++; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::DerefMemory: m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); code_offset += 2; break; case eOperandType::DerefRegister: m_code.push_back((uint8_t)word2); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { if (opType2 == eOperandType::DerefMemory) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wmem_immoffw_in_reg; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_immoffw_in_reg; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { if (opType2 == eOperandType::DerefMemory) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wmem_immoffb_in_reg; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_immoffb_in_reg; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: if (opType2 == eOperandType::DerefMemory) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wmem_regoff_in_reg; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_regoff_in_reg; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::DerefRegister) { m_code.push_back((uint8_t)word1); code_offset++; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::DerefRegister: m_code.push_back((uint8_t)word2); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_immoffw_in_dreg; m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_immoffb_in_dreg; m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::wdreg_regoff_in_dreg; m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> DerefRegister or Pointer required\n"; exit(0); return; } } else if (instEdit == "movbo") { m_code.push_back(data::OpCodes::Ext01); m_code.push_back(0x00); if (st.count() != 3) { std::cout << "Invalid operand number; " << line << "3 -> 3 required\n"; exit(0); return; } eOperandType opType1 = parseOperand(st.next(), word1); if (opType1 == eOperandType::Register) { m_code.push_back((uint8_t)word1); code_offset++; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::DerefMemory: m_code.push_back((uint8_t)((word2 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word2 & 0x00FF)); code_offset += 2; break; case eOperandType::DerefRegister: m_code.push_back((uint8_t)word2); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { if (opType2 == eOperandType::DerefMemory) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bmem_immoffw_in_reg; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_immoffw_in_reg; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { if (opType2 == eOperandType::DerefMemory) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bmem_immoffb_in_reg; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_immoffb_in_reg; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: if (opType2 == eOperandType::DerefMemory) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bmem_regoff_in_reg; else if (opType2 == eOperandType::DerefRegister) m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_regoff_in_reg; else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); } m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else if (opType1 == eOperandType::DerefRegister) { m_code.push_back((uint8_t)word1); code_offset++; eOperandType opType2 = parseOperand(st.next(), word2); ostd::String op3 = st.next(); bool word_offset = false; if (op3.startsWith("word")) { op3.substr(4).trim(); word_offset = true; } eOperandType opType3 = parseOperand(op3, word3); switch (opType2) { case eOperandType::DerefRegister: m_code.push_back((uint8_t)word2); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } switch (opType3) { case eOperandType::Immediate: case eOperandType::Label: if (word_offset) { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_immoffw_in_dreg; m_code.push_back((uint8_t)((word3 & 0xFF00) >> 8)); m_code.push_back((uint8_t)(word3 & 0x00FF)); code_offset += 2; } else { m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_immoffb_in_dreg; m_code.push_back((uint8_t)word3); code_offset++; } break; case eOperandType::Register: m_code[m_code.size() - code_offset] = hw::cpuext::ExtMov::OpCodes::bdreg_regoff_in_dreg; m_code.push_back((uint8_t)word3); code_offset++; break; default: std::cout << "Invalid operand type; " << line << " (" << opEdit << ")\n"; exit(0); break; } } else { std::cout << "Invalid operand type; " << line << " (" << opEdit << ") -> DerefRegister or Pointer required\n"; exit(0); return; } } return; } else if (instEdit == "omov" || instEdit == "omovb" || instEdit == "movo" || instEdit == "movbo") { std::cout << "ExtMov instruction detected, please add '--extmov' flag to dasm.\n"; exit(0); return; } } void Assembler::combineDataAndCode(void) { uint16_t entryAddr = m_dataSize + m_loadAddress + 3; std::vector symbols; ostd::ByteStream newCode; newCode.push_back(data::OpCodes::Jmp); newCode.push_back((uint8_t)((entryAddr & 0xFF00) >> 8)); newCode.push_back((uint8_t)(entryAddr & 0x00FF)); if (m_dataSize > 0) m_disassembly.insert(m_disassembly.begin(), { (uint16_t)(m_loadAddress + 3), "[----------DATA_SECTION----------]" }); m_disassembly.insert(m_disassembly.begin(), { m_loadAddress, ostd::String("jmp ").add(ostd::Utils::getHexStr(entryAddr, true, 2)) }); for (auto& d : m_symbolTable) { symbols.push_back(d.second); for (int32_t i = 0; i < d.second.bytes.size(); i++) newCode.push_back(0x00); } for (int32_t i = symbols.size() - 1; i >= 0; i--) { for (int32_t j = 0; j < symbols[i].bytes.size(); j++) newCode[symbols[i].address - m_loadAddress + j] = symbols[i].bytes[j]; } for (auto& b : m_code) newCode.push_back(b); m_code = newCode; m_disassembly.push_back({ 0xFFFFFF00, "{ DATA }" }); for (auto& d : m_symbolTable) { m_disassembly.push_back({ d.second.address, d.first, (uint16_t)d.second.bytes.size() }); } m_disassembly.push_back({ 0xFFFFFF01, "{ LABELS }" }); for (auto& l : m_labelTable) { m_disassembly.push_back({ l.second.address, l.first }); } } ostd::String Assembler::replaceSymbols(ostd::String line) { ostd::String lineEdit(line); for (auto& symbol : m_symbolTable) { ostd::String regex = "\\" + symbol.first.new_regexReplace("\\.", "\\.") + "(?!\\.)(?!\\w)"; // std::cout << "SYMBOL: " << symbol.first << "\n"; // std::cout << "LINE: " << lineEdit << "\n"; // std::cout << "REGEX: " << regex << "\n"; lineEdit.regexReplace(regex, ostd::Utils::getHexStr(symbol.second.address, true, 2), false); // std::cout << "NEW_LINE: " << lineEdit << "\n\n"; } return lineEdit; } void Assembler::replaceLabelRefs(void) { for (auto& label : m_labelTable) { for (auto& addr : label.second.references) { m_code[addr] = (uint8_t)((label.second.address & 0xFF00) >> 8); m_code[addr + 1] = (uint8_t)(label.second.address & 0x00FF); } } } Assembler::eOperandType Assembler::parseOperand(ostd::String op, int16_t& outOp) { ostd::String opEdit(op); bool derefReg = false; if (opEdit.startsWith("*")) { opEdit = opEdit.substr(1); opEdit.trim(); derefReg = true; } int8_t reg = parseRegister(opEdit); if (reg != data::Registers::Last) { outOp = (int16_t)reg; if (derefReg) return eOperandType::DerefRegister; return eOperandType::Register; } else if (opEdit.startsWith("reg(") && opEdit.endsWith(")")) { opEdit.substr(4, opEdit.len() - 1); opEdit.trim(); if (!opEdit.isNumeric()) { std::cout << "Invalid numeric value: " << opEdit << "\n"; return eOperandType::Error; } uint8_t _reg = opEdit.toInt(); if (_reg >= data::Registers::Last) { std::cout << "Invalid Register: " << opEdit << "\n"; return eOperandType::Error; } outOp = (int16_t)_reg; if (derefReg) return eOperandType::DerefRegister; return eOperandType::Register; } if (derefReg) { std::cout << "Invalid Register Dereferencing: " << op << "\n"; return eOperandType::Error; } if (opEdit.isNumeric()) { outOp = (int16_t)opEdit.toInt(); return eOperandType::Immediate; } if (opEdit.startsWith("$")) { if (m_labelTable.count(opEdit) == 0) { std::cout << "Unknown symbol: " << opEdit << "\n"; return eOperandType::Error; } uint16_t labelAddr = m_labelTable[opEdit].address; if (labelAddr == 0x0000) m_labelTable[opEdit].references.push_back(m_code.size()); outOp = (int16_t)labelAddr; return eOperandType::Label; } if (opEdit.startsWith("{") && opEdit.endsWith("}")) { opEdit = opEdit.substr(1, opEdit.len() - 1); opEdit.trim(); outOp = (int16_t)ostd::Utils::solveIntegerExpression(opEdit); return eOperandType::Immediate; } if (opEdit.startsWith("[") && opEdit.endsWith("]")) { opEdit = opEdit.substr(1, opEdit.len() - 1); opEdit.trim(); if (opEdit.startsWith("{") && opEdit.endsWith("}")) { opEdit = opEdit.substr(1, opEdit.len() - 1); opEdit.trim(); outOp = (int16_t)ostd::Utils::solveIntegerExpression(opEdit); return eOperandType::DerefMemory; } if (!opEdit.isNumeric()) { std::cout << "Invalid numeric value: " << opEdit << "\n"; return eOperandType::Error; } outOp = (int16_t)opEdit.toInt(); return eOperandType::DerefMemory; } return eOperandType::Error; } uint8_t Assembler::parseRegister(ostd::String op) { ostd::String opEdit(op); opEdit.trim().toLower(); if (opEdit == "r1") return data::Registers::R1; if (opEdit == "r2") return data::Registers::R2; if (opEdit == "r3") return data::Registers::R3; if (opEdit == "r4") return data::Registers::R4; if (opEdit == "r5") return data::Registers::R5; if (opEdit == "r6") return data::Registers::R6; if (opEdit == "r7") return data::Registers::R7; if (opEdit == "r8") return data::Registers::R8; if (opEdit == "r9") return data::Registers::R9; if (opEdit == "r10") return data::Registers::R10; if (opEdit == "acc") return data::Registers::ACC; if (opEdit == "fp") return data::Registers::FP; if (opEdit == "sp") return data::Registers::SP; if (opEdit == "ip") return data::Registers::IP; if (opEdit == "pp") return data::Registers::PP; if (opEdit == "rv") return data::Registers::RV; if (opEdit == "fl") return data::Registers::FL; return data::Registers::Last; } void Assembler::printProgramInfo(void) { int32_t symbol_len = 30; out.nl(); if (m_symbolTable.size() > 0) out.fg(ostd::ConsoleColors::Yellow).p("Symbols:").nl(); for (auto& symbol : m_symbolTable) { out.fg(ostd::ConsoleColors::Red).p(ostd::Utils::getHexStr(symbol.second.address, true, 2)); out.fg(ostd::ConsoleColors::Magenta).p(" ").p(symbol.first); out.fg(ostd::ConsoleColors::Blue).nl().p(" "); for (auto& b : symbol.second.bytes) out.p(ostd::Utils::getHexStr(b, false, 1)).p("."); out.nl(); } if (m_symbolTable.size() > 0) out.nl(); if (m_labelTable.size() > 0) out.fg(ostd::ConsoleColors::Yellow).p("Labels:").nl(); for (auto& label : m_labelTable) { out.fg(ostd::ConsoleColors::Magenta).p(label.first.new_fixedLength(symbol_len)); out.fg(ostd::ConsoleColors::Red).p(ostd::Utils::getHexStr(label.second.address, true, 2)).nl(); } if (m_labelTable.size() > 0) out.nl(); if (m_structDefs.size() > 0) out.fg(ostd::ConsoleColors::Yellow).p("Structures:").nl(); for (auto& str : m_structDefs) { out.fg(ostd::ConsoleColors::Magenta).p(str.name.new_fixedLength(symbol_len)); out.fg(ostd::ConsoleColors::Red).p(str.size).p(" bytes").nl(); } if (m_structDefs.size() > 0) out.nl(); out.fg(ostd::ConsoleColors::Yellow).p("Program data:").nl(); out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Fixed Size: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p((int)m_fixedSize).p(" bytes").nl(); out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Program Size:").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p((int)m_programSize).p(" bytes").nl(); out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Data Size: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p((int)m_dataSize).p(" bytes").nl(); out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Fixed Fill: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(m_fixedFillValue, true, 1)).nl(); out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Load Address:").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(m_loadAddress, true, 2)).nl(); out.fg(ostd::ConsoleColors::Cyan).p(ostd::String("Entry Point: ").new_fixedLength(symbol_len)).fg(ostd::ConsoleColors::BrightRed).p(ostd::Utils::getHexStr(m_dataSize + m_loadAddress + 3, true, 2)).nl(); out.nl(); } } }