diff --git a/Makefile b/Makefile index 39fae9b..cd593b8 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ LDFLAGS = TARGET = CXX = $(TARGET)g++ -OBJS = main.o fromstring.o addressing_mode.o codec.o parser.o -HEADERS = $(wildcard *.h) +OBJS = main.o tostring.o fromstring.o addressing_mode.o codec.o parser.o symbol.o +HEADERS = $(wildcard *.hh) all: main diff --git a/assembler.hh b/assembler.hh index 5d26e38..212a232 100644 --- a/assembler.hh +++ b/assembler.hh @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "isa.hh" @@ -24,7 +26,27 @@ namespace assembler { isa::mode mode; std::variant value; size_t location; + ssize_t row; // debug }; - using program_t = std::vector; + struct blob_t { + struct { + size_t start; + size_t start_l; + size_t start_h; + size_t size_l; + size_t size_h; + } symbol; + size_t location; + std::shared_ptr buf; + }; + + using program_t = std::vector>; + + struct symbol_strings_t { + size_t current_symbol; + std::unordered_map map; + }; + + using symbol_table_t = std::unordered_map; } diff --git a/codec.cc b/codec.cc index 083d6c4..2d24abe 100644 --- a/codec.cc +++ b/codec.cc @@ -10,7 +10,7 @@ namespace codec { const std::map, uint8_t>& encode() { static const std::map, uint8_t> _ = { {{isa::op::BRK, isa::mode::S}, 0}, - {{isa::op::ORA, isa::mode::ZPX}, 1}, + {{isa::op::ORA, isa::mode::ZPII}, 1}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 2}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 3}, {{isa::op::TSB, isa::mode::ZP}, 4}, @@ -19,7 +19,7 @@ namespace codec { {{isa::op::RMB0, isa::mode::ZP}, 7}, {{isa::op::PHP, isa::mode::S}, 8}, {{isa::op::ORA, isa::mode::IMM}, 9}, - {{isa::op::ASL, isa::mode::A}, 10}, + {{isa::op::ASL, isa::mode::ACC}, 10}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 11}, {{isa::op::TSB, isa::mode::A}, 12}, {{isa::op::ORA, isa::mode::A}, 13}, @@ -36,7 +36,7 @@ namespace codec { {{isa::op::RMB1, isa::mode::ZP}, 23}, {{isa::op::CLC, isa::mode::I}, 24}, {{isa::op::ORA, isa::mode::AIY}, 25}, - {{isa::op::INC, isa::mode::A}, 26}, + {{isa::op::INC, isa::mode::ACC}, 26}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 27}, {{isa::op::TRB, isa::mode::A}, 28}, {{isa::op::ORA, isa::mode::AIX}, 29}, @@ -53,7 +53,7 @@ namespace codec { {{isa::op::RMB2, isa::mode::ZP}, 39}, {{isa::op::PLP, isa::mode::S}, 40}, {{isa::op::AND, isa::mode::IMM}, 41}, - {{isa::op::ROL, isa::mode::A}, 42}, + {{isa::op::ROL, isa::mode::ACC}, 42}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 43}, {{isa::op::BIT, isa::mode::A}, 44}, {{isa::op::AND, isa::mode::A}, 45}, @@ -70,7 +70,7 @@ namespace codec { {{isa::op::RMB3, isa::mode::ZP}, 55}, {{isa::op::SEC, isa::mode::I}, 56}, {{isa::op::AND, isa::mode::AIY}, 57}, - {{isa::op::DEC, isa::mode::A}, 58}, + {{isa::op::DEC, isa::mode::ACC}, 58}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 59}, {{isa::op::BIT, isa::mode::AIX}, 60}, {{isa::op::AND, isa::mode::AIX}, 61}, @@ -87,7 +87,7 @@ namespace codec { {{isa::op::RMB4, isa::mode::ZP}, 71}, {{isa::op::PHA, isa::mode::S}, 72}, {{isa::op::EOR, isa::mode::IMM}, 73}, - {{isa::op::LSR, isa::mode::A}, 74}, + {{isa::op::LSR, isa::mode::ACC}, 74}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 75}, {{isa::op::JMP, isa::mode::A}, 76}, {{isa::op::EOR, isa::mode::A}, 77}, @@ -121,7 +121,7 @@ namespace codec { {{isa::op::RMB6, isa::mode::ZP}, 103}, {{isa::op::PLA, isa::mode::S}, 104}, {{isa::op::ADC, isa::mode::IMM}, 105}, - {{isa::op::ROR, isa::mode::A}, 106}, + {{isa::op::ROR, isa::mode::ACC}, 106}, //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 107}, {{isa::op::JMP, isa::mode::AI}, 108}, {{isa::op::ADC, isa::mode::A}, 109}, @@ -287,7 +287,7 @@ namespace codec { const std::map>& decode() { static const std::map> _ = { {0, {isa::op::BRK, isa::mode::S}}, - {1, {isa::op::ORA, isa::mode::ZPX}}, + {1, {isa::op::ORA, isa::mode::ZPII}}, //{2, {isa::op::O_INVALID, isa::mode::M_INVALID}}, //{3, {isa::op::O_INVALID, isa::mode::M_INVALID}}, {4, {isa::op::TSB, isa::mode::ZP}}, @@ -296,7 +296,7 @@ namespace codec { {7, {isa::op::RMB0, isa::mode::ZP}}, {8, {isa::op::PHP, isa::mode::S}}, {9, {isa::op::ORA, isa::mode::IMM}}, - {10, {isa::op::ASL, isa::mode::A}}, + {10, {isa::op::ASL, isa::mode::ACC}}, //{11, {isa::op::O_INVALID, isa::mode::M_INVALID}}, {12, {isa::op::TSB, isa::mode::A}}, {13, {isa::op::ORA, isa::mode::A}}, @@ -313,7 +313,7 @@ namespace codec { {23, {isa::op::RMB1, isa::mode::ZP}}, {24, {isa::op::CLC, isa::mode::I}}, {25, {isa::op::ORA, isa::mode::AIY}}, - {26, {isa::op::INC, isa::mode::A}}, + {26, {isa::op::INC, isa::mode::ACC}}, //{27, {isa::op::O_INVALID, isa::mode::M_INVALID}}, {28, {isa::op::TRB, isa::mode::A}}, {29, {isa::op::ORA, isa::mode::AIX}}, @@ -330,7 +330,7 @@ namespace codec { {39, {isa::op::RMB2, isa::mode::ZP}}, {40, {isa::op::PLP, isa::mode::S}}, {41, {isa::op::AND, isa::mode::IMM}}, - {42, {isa::op::ROL, isa::mode::A}}, + {42, {isa::op::ROL, isa::mode::ACC}}, //{43, {isa::op::O_INVALID, isa::mode::M_INVALID}}, {44, {isa::op::BIT, isa::mode::A}}, {45, {isa::op::AND, isa::mode::A}}, @@ -347,7 +347,7 @@ namespace codec { {55, {isa::op::RMB3, isa::mode::ZP}}, {56, {isa::op::SEC, isa::mode::I}}, {57, {isa::op::AND, isa::mode::AIY}}, - {58, {isa::op::DEC, isa::mode::A}}, + {58, {isa::op::DEC, isa::mode::ACC}}, //{59, {isa::op::O_INVALID, isa::mode::M_INVALID}}, {60, {isa::op::BIT, isa::mode::AIX}}, {61, {isa::op::AND, isa::mode::AIX}}, @@ -364,7 +364,7 @@ namespace codec { {71, {isa::op::RMB4, isa::mode::ZP}}, {72, {isa::op::PHA, isa::mode::S}}, {73, {isa::op::EOR, isa::mode::IMM}}, - {74, {isa::op::LSR, isa::mode::A}}, + {74, {isa::op::LSR, isa::mode::ACC}}, //{75, {isa::op::O_INVALID, isa::mode::M_INVALID}}, {76, {isa::op::JMP, isa::mode::A}}, {77, {isa::op::EOR, isa::mode::A}}, @@ -398,7 +398,7 @@ namespace codec { {103, {isa::op::RMB6, isa::mode::ZP}}, {104, {isa::op::PLA, isa::mode::S}}, {105, {isa::op::ADC, isa::mode::IMM}}, - {106, {isa::op::ROR, isa::mode::A}}, + {106, {isa::op::ROR, isa::mode::ACC}}, //{107, {isa::op::O_INVALID, isa::mode::M_INVALID}}, {108, {isa::op::JMP, isa::mode::AI}}, {109, {isa::op::ADC, isa::mode::A}}, diff --git a/main.cc b/main.cc index da8f49a..12d6f10 100644 --- a/main.cc +++ b/main.cc @@ -2,83 +2,69 @@ #include #include #include +#include #include "assembler.hh" #include "addressing_mode.hh" #include "codec.hh" #include "parser.hh" +#include "tostring.hh" +#include "symbol.hh" -using symbol_table_t = std::unordered_map; +using namespace std::literals; -bool resolve_symbols(assembler::program_t& program, symbol_table_t& symbol_table) +void serialize_program(const assembler::program_t& program, const assembler::symbol_table_t &symbol_table, std::ostream& out) { - size_t offset = 0; + auto serialize_instruction = [&](assembler::instruction_t& ins) -> void { + //std::cerr << "enc " << (int)ins.op << ' ' << (int)ins.mode << '\n'; + char buf[3]; - for (auto ins = program.begin(); ins != program.end(); ins++) { - if (ins->symbol != std::nullopt) { - auto [_, ok] = symbol_table.insert({*(ins->symbol), ins}); - if (!ok) { - std::cout << "duplicate symbol\n"; - return false; - } - - std::cout << *(ins->symbol) << ' ' << offset << '\n'; + auto opcode_it = codec::encode().find({ins.op, ins.mode}); + if (opcode_it == codec::encode().end()) { + std::cerr << ins.row << ": illegal op,mode: " + << tostring::op().find(ins.op)->second << ' ' + << tostring::mode().find(ins.mode)->second << '\n'; + return; } - ins->location = offset; - - auto am_it = addressing_mode().find(ins->mode); - assert (am_it != addressing_mode().end()); - offset += 1 + am_it->second.len; - } - - return true; -} - -void serialize_program(const assembler::program_t& program, const symbol_table_t &symbol_table, size_t link_location, std::ostream& out) -{ - char buf[3]; - - for (auto ins = program.cbegin(); ins != program.cend(); ins++) { - std::cerr << "enc " << (int)ins->op << ' ' << (int)ins->mode << '\n'; - auto opcode_it = codec::encode().find({ins->op, ins->mode}); - assert (opcode_it != codec::encode().end()); - buf[0] = opcode_it->second; - auto am_it = addressing_mode().find(ins->mode); + auto am_it = addressing_mode().find(ins.mode); assert (am_it != addressing_mode().end()); auto get_value = [&]() -> ssize_t { - if (std::holds_alternative(ins->value)) { - assembler::reference_t ref = std::get(ins->value); + if (std::holds_alternative(ins.value)) { + assembler::reference_t ref = std::get(ins.value); auto sym_it = symbol_table.find(ref.symbol); - assert (sym_it != symbol_table.end()); - auto ref_ins = sym_it->second; - if (ins->mode == isa::mode::R) { - std::cout << "relative\n"; - ssize_t offset = static_cast(ref_ins->location) - static_cast(ins->location + 2); + if (sym_it == symbol_table.end()) { + std::cerr << "get_value: " << ref.symbol << '\n'; + assert(false); + } + auto ref_location = sym_it->second; + if (ins.mode == isa::mode::R) { + ssize_t offset = static_cast(ref_location) - static_cast(ins.location + 2); return offset; } else { - return ref_ins->location + link_location; + return ref_location; } - } else if (std::holds_alternative(ins->value)) { - assembler::literal_t lit = std::get(ins->value); + } else if (std::holds_alternative(ins.value)) { + assembler::literal_t lit = std::get(ins.value); return lit.num; - } else if (std::holds_alternative(ins->value)) { - assert (std::holds_alternative(ins->value)); + } else if (std::holds_alternative(ins.value)) { + //assert (std::holds_alternative(ins.value)); + return 0; } else { assert (false); } - return 0; }; size_t value = get_value(); if (!am_it->second.valid(value)) { - std::cout << "overflow at h" << std::hex << ins->location << '\n'; + std::cerr << "overflow at " << ins.row << " value: " << value << '\n'; + return; } - std::cout << "value " << std::hex << value << ' ' << am_it->second.len << '\n'; + //std::cerr << "value " << std::hex << value << ' ' << am_it->second.len << '\n'; if (am_it->second.len >= 2) buf[2] = (value >> 8) & 0xff; @@ -86,6 +72,19 @@ void serialize_program(const assembler::program_t& program, const symbol_table_t buf[1] = (value >> 0) & 0xff; out.write(buf, 1 + am_it->second.len); + }; + + + for (auto prog_it = program.cbegin(); prog_it != program.cend(); prog_it++) { + if (std::holds_alternative(*prog_it)) { + auto ins = std::get(*prog_it); + serialize_instruction(ins); + } else if (std::holds_alternative(*prog_it)) { + auto blob = std::get(*prog_it); + out.write(blob.buf->data(), blob.buf->size()); + } else { + assert (false); + } } } @@ -96,41 +95,66 @@ int main(int argc, char * argv[]) return -1; } - std::string input_filename {argv[1]}; - std::ifstream is {input_filename, std::ios::binary | std::ios::ate}; - if (!is.is_open()) { - std::cerr << "failed to open " << input_filename << '\n'; - return -1; - } - - auto size = is.tellg(); - std::string buf(size, '\0'); // construct string to stream size - is.seekg(0); - is.read(buf.data(), size); - is.close(); - - assembler::program_t program; - symbol_table_t symbol_table; + assembler::symbol_strings_t symbol_strings; + symbol_strings.current_symbol = 0; + assembler::symbol_table_t symbol_table; + bool ok; - ok = parser::parse(buf, program); + for (int i = 1; i < (argc - 1); i++) { + std::cerr << "input[" << i << "]: " << argv[i] << '\n'; + std::string input_filename {argv[i]}; + std::ifstream is {input_filename, std::ios::binary | std::ios::ate}; + if (!is.is_open()) { + std::cerr << "failed to open " << input_filename << '\n'; + return -1; + } + + auto size = is.tellg(); + auto buf = std::make_unique(size, '\0'); // construct string to stream size + is.seekg(0); + is.read(buf->data(), size); + is.close(); + + std::string_view ext = input_filename.substr(input_filename.size() - 4, 4); + if (ext == ".asm"s) { + ok = parser::parse(*buf, program, symbol_strings); + if (!ok) + return -1; + } else if (ext == ".bin"s) { + std::string name = input_filename.substr(0, input_filename.size() - 4); + assembler::blob_t blob { + .symbol = { + .start = symbol::get(symbol_strings, "_bin_"s + name + "_start"s), + .start_l = symbol::get(symbol_strings, "_bin_"s + name + "_start_l"s), + .start_h = symbol::get(symbol_strings, "_bin_"s + name + "_start_h"s), + .size_l = symbol::get(symbol_strings, "_bin_"s + name + "_size_l"s), + .size_h = symbol::get(symbol_strings, "_bin_"s + name + "_size_h"s), + }, + .location = 0xeeee, + .buf = std::move(buf), + }; + program.push_back(blob); + } else { + std::cerr << "unknown extension: " << ext << '\n'; + return -1; + } + } + + ok = symbol::resolve(0xc000, program, symbol_table); if (!ok) return -1; - ok = resolve_symbols(program, symbol_table); - if (!ok) - return -1; - - - std::string output_filename {argv[2]}; + std::cerr << "output: " << argv[argc - 1] << '\n'; + std::string output_filename {argv[argc - 1]}; std::ofstream out {output_filename, std::ios::binary}; if (!out.is_open()) { std::cerr << "failed to open " << output_filename << '\n'; return -1; } - serialize_program(program, symbol_table, 0x8200, out); + serialize_program(program, symbol_table, out); out.close(); return 0; diff --git a/parser.cc b/parser.cc index 2be279b..2acb3f9 100644 --- a/parser.cc +++ b/parser.cc @@ -8,6 +8,7 @@ #include "addressing_mode.hh" #include "fromstring.hh" #include "isa.hh" +#include "symbol.hh" static bool tokenize(std::string_view buf, std::function cb) { @@ -68,30 +69,14 @@ namespace parser { }; } -using symbol_strings_t = std::unordered_map; - namespace parser { -bool parse(std::string_view buf, assembler::program_t& program) +bool parse(std::string_view buf, assembler::program_t& program, assembler::symbol_strings_t& symbol_strings) { - size_t current_symbol = 0; - symbol_strings_t ss; - parser::state state = parser::state::label_or_op; - auto get_symbol = [&](std::string_view s) { - auto find = ss.find(s); - if (find == ss.end()) { - auto insert = ss.insert({s, current_symbol++}); - assert(insert.second); - return (insert.first)->second; - } else { - return find->second; - } - }; - assembler::instruction_t current_instruction; - ssize_t current_row; + current_instruction.location = 0xeeee; bool inside_comment = false; @@ -100,11 +85,11 @@ bool parse(std::string_view buf, assembler::program_t& program) switch (state) { case parser::state::label_or_op: { - current_row = row; + current_instruction.row = row; if (s.back() == ':') { std::string_view key = s.substr(0, s.length() - 1); - auto symbol = get_symbol(key); - std::cerr << "label `" << symbol << "`\n"; + auto symbol = symbol::get(symbol_strings, key); + //std::cerr << "label `" << symbol << "`\n"; current_instruction.symbol = symbol; state = parser::state::op; return true; @@ -121,28 +106,28 @@ bool parse(std::string_view buf, assembler::program_t& program) } case parser::state::op: { - assert(row == current_row); + assert(row == current_instruction.row); auto op_it = fromstring::op().find(s); if (op_it == fromstring::op().end()) { - std::cerr << "invalid op `" << s << "`\n"; + std::cerr << row << ',' << col << ": invalid op `" << s << "`\n"; return false; } else { current_instruction.op = op_it->second; - std::cerr << "ok op `" << static_cast(op_it->second) << "`\n"; + //std::cerr << row << ": ok op `" << static_cast(op_it->second) << "`\n"; } state = parser::state::mode; return true; } case parser::state::mode: { - assert(row == current_row); + assert(row == current_instruction.row); auto mode_it = fromstring::mode().find(s); if (mode_it == fromstring::mode().end()) { - std::cerr << "invalid mode `" << s << "`\n"; + std::cerr << row << ',' << col << ": invalid mode `" << s << "`\n"; return false; } else { current_instruction.mode = mode_it->second; - std::cerr << "ok mode `" << static_cast(mode_it->second) << "`\n"; + //std::cerr << "ok mode `" << static_cast(mode_it->second) << "`\n"; } state = parser::state::value; return true; @@ -152,14 +137,14 @@ bool parse(std::string_view buf, assembler::program_t& program) auto am_it = addressing_mode().find(current_instruction.mode); assert(am_it != addressing_mode().end()); if (am_it->second.len == 0) { - std::cerr << "no value expected\n"; + //std::cerr << row << ',' << col << ": no value expected\n"; assembler::implied_t i {}; current_instruction.value = i; state = parser::state::comment; continue; } - assert(row == current_row); + assert(row == current_instruction.row); auto parse_integer = [](std::string_view s, int base) -> std::optional { std::string value_str {s.data(), s.length()}; @@ -185,52 +170,62 @@ bool parse(std::string_view buf, assembler::program_t& program) case '7': case '8': case '9': - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': { literal = parse_integer(s, 16); if (literal == std::nullopt) { - std::cerr << row << ": invalid hex literal\n"; + std::cerr << row << ',' << col << ": invalid hex literal\n"; } current_instruction.value = as_literal(*literal); - std::cerr << "value hex literal `" << *literal << "`\n"; + //std::cerr << "value hex literal `" << *literal << "`\n"; break; } - case 'h': + case '%': + { + literal = parse_integer(s.substr(1, s.length() - 1), 2); + if (literal == std::nullopt) { + std::cerr << row << ',' << col << ": invalid bin literal\n"; + } + current_instruction.value = as_literal(*literal); + //std::cerr << "value bin literal `" << *literal << "`\n"; + break; + } + case '$': { literal = parse_integer(s.substr(1, s.length() - 1), 16); if (literal == std::nullopt) { - std::cerr << row << ": invalid hex literal\n"; + std::cerr << row << ',' << col << ": invalid hex literal\n"; } current_instruction.value = as_literal(*literal); - std::cerr << "value hex literal `" << *literal << "`\n"; + //std::cerr << "value hex literal `" << *literal << "`\n"; break; } - case 'd': + case 'i': { literal = parse_integer(s.substr(1, s.length() - 1), 10); if (literal == std::nullopt) { - std::cerr << row << ": invalid dec literal\n"; + std::cerr << row << ',' << col << ": invalid dec literal\n"; return false; } current_instruction.value = as_literal(*literal); - std::cerr << "value dec literal `" << *literal << "`\n"; + //std::cerr << "value dec literal `" << *literal << "`\n"; break; } case ':': { std::string_view key = s.substr(1, s.length() - 1); - assembler::reference_t reference = { get_symbol(key) }; + assembler::reference_t reference = { symbol::get(symbol_strings, key) }; current_instruction.value = reference; - std::cerr << "value reference `" << reference.symbol << "`\n"; + //std::cerr << "value reference `" << reference.symbol << "`\n"; break; } default: - std::cerr << row << ": invalid base\n"; + std::cerr << row << ',' << col << ": invalid base\n"; return false; } @@ -239,8 +234,8 @@ bool parse(std::string_view buf, assembler::program_t& program) } case parser::state::comment: { - if (row != current_row) { - std::cerr << "push " << (int)current_instruction.op << '\n'; + if (row != current_instruction.row) { + //std::cerr << "push " << (int)current_instruction.op << '\n'; inside_comment = false; program.push_back(current_instruction); state = parser::state::label_or_op; @@ -253,13 +248,13 @@ bool parse(std::string_view buf, assembler::program_t& program) } else if (inside_comment) { return true; } else { - std::cerr << row << ": expected comment\n"; + std::cerr << row << ',' << col << ": expected comment\n"; return false; } } case parser::state::just_comment: { - if (row != current_row) { + if (row != current_instruction.row) { inside_comment = false; state = parser::state::label_or_op; continue; @@ -271,7 +266,7 @@ bool parse(std::string_view buf, assembler::program_t& program) } else if (inside_comment) { return true; } else { - std::cerr << "expected comment\n"; + std::cerr << row << ',' << col << ": expected comment\n"; return false; } } diff --git a/parser.hh b/parser.hh index e7abcd3..a4e61de 100644 --- a/parser.hh +++ b/parser.hh @@ -5,5 +5,5 @@ #include "assembler.hh" namespace parser { - bool parse(std::string_view buf, assembler::program_t& program); + bool parse(std::string_view buf, assembler::program_t& program, assembler::symbol_strings_t& symbol_strings); } diff --git a/symbol.cc b/symbol.cc new file mode 100644 index 0000000..2626ed8 --- /dev/null +++ b/symbol.cc @@ -0,0 +1,63 @@ +#include +#include +#include + +#include "assembler.hh" +#include "addressing_mode.hh" + +namespace symbol { + +size_t get(assembler::symbol_strings_t& symbol_strings, std::string_view s) { + std::string key {s}; + auto find = symbol_strings.map.find(key); + if (find == symbol_strings.map.end()) { + std::cerr << "get new: " << s << ' ' << symbol_strings.current_symbol << '\n'; + auto insert = symbol_strings.map.insert({key, symbol_strings.current_symbol++}); + assert(insert.second); + return (insert.first)->second; + } else { + return find->second; + } +} + +bool resolve(size_t link_location, assembler::program_t& program, assembler::symbol_table_t& symbol_table) +{ + size_t offset = link_location; + + for (auto prog_it = program.begin(); prog_it != program.end(); prog_it++) { + if (std::holds_alternative(*prog_it)) { + auto& ins = std::get(*prog_it); + ins.location = offset; + if (ins.symbol != std::nullopt) { + auto [_, ok] = symbol_table.insert({*(ins.symbol), offset}); + if (!ok) { + std::cerr << ins.row << ": duplicate symbol\n"; + return false; + } + } + + auto am_it = addressing_mode().find(ins.mode); + assert (am_it != addressing_mode().end()); + offset += 1 + am_it->second.len; + } else if (std::holds_alternative(*prog_it)) { + auto& blob = std::get(*prog_it); + blob.location = offset + 4; + auto [_1, ok1] = symbol_table.insert({blob.symbol.start, offset}); + auto [_2, ok2] = symbol_table.insert({blob.symbol.start_l, (offset >> 0) & 0xff}); + auto [_3, ok3] = symbol_table.insert({blob.symbol.start_h, (offset >> 8) & 0xff}); + auto [_4, ok4] = symbol_table.insert({blob.symbol.size_l, (blob.buf->size() >> 0) & 0xff}); + auto [_5, ok5] = symbol_table.insert({blob.symbol.size_h, (blob.buf->size() >> 8) & 0xff}); + if (!ok1 || !ok2 || !ok3 || !ok4 || !ok5) { + std::cerr << "duplicate blob symbol\n"; + return false; + } + offset += 4 + blob.buf->size(); + } else { + assert(false); + } + } + + return true; +} + +} diff --git a/symbol.hh b/symbol.hh new file mode 100644 index 0000000..66c7a66 --- /dev/null +++ b/symbol.hh @@ -0,0 +1,11 @@ +#include + +#include "assembler.hh" + +namespace symbol { + +size_t get(assembler::symbol_strings_t& symbol_strings, std::string_view s); + +bool resolve(size_t link_location, assembler::program_t& program, assembler::symbol_table_t& symbol_table); + +} diff --git a/tostring.cc b/tostring.cc index b5e84a4..17de7af 100644 --- a/tostring.cc +++ b/tostring.cc @@ -1,127 +1,133 @@ -#include +#include #include -#include "instruction.hh" +#include "isa.hh" #include "mneumonic.hh" namespace tostring { - const std::unordered_map op { - {op::ADC, mneumonic::op::ADC}, - {op::AND, mneumonic::op::AND}, - {op::ASL, mneumonic::op::ASL}, - {op::BBR0, mneumonic::op::BBR0}, - {op::BBR1, mneumonic::op::BBR1}, - {op::BBR2, mneumonic::op::BBR2}, - {op::BBR3, mneumonic::op::BBR3}, - {op::BBR4, mneumonic::op::BBR4}, - {op::BBR5, mneumonic::op::BBR5}, - {op::BBR6, mneumonic::op::BBR6}, - {op::BBR7, mneumonic::op::BBR7}, - {op::BBS0, mneumonic::op::BBS0}, - {op::BBS1, mneumonic::op::BBS1}, - {op::BBS2, mneumonic::op::BBS2}, - {op::BBS3, mneumonic::op::BBS3}, - {op::BBS4, mneumonic::op::BBS4}, - {op::BBS5, mneumonic::op::BBS5}, - {op::BBS6, mneumonic::op::BBS6}, - {op::BBS7, mneumonic::op::BBS7}, - {op::BCC, mneumonic::op::BCC}, - {op::BCS, mneumonic::op::BCS}, - {op::BEQ, mneumonic::op::BEQ}, - {op::BIT, mneumonic::op::BIT}, - {op::BMI, mneumonic::op::BMI}, - {op::BNE, mneumonic::op::BNE}, - {op::BPL, mneumonic::op::BPL}, - {op::BRA, mneumonic::op::BRA}, - {op::BRK, mneumonic::op::BRK}, - {op::BVC, mneumonic::op::BVC}, - {op::BVS, mneumonic::op::BVS}, - {op::CLC, mneumonic::op::CLC}, - {op::CLD, mneumonic::op::CLD}, - {op::CLI, mneumonic::op::CLI}, - {op::CLV, mneumonic::op::CLV}, - {op::CMP, mneumonic::op::CMP}, - {op::CPX, mneumonic::op::CPX}, - {op::CPY, mneumonic::op::CPY}, - {op::DEC, mneumonic::op::DEC}, - {op::DEX, mneumonic::op::DEX}, - {op::DEY, mneumonic::op::DEY}, - {op::EOR, mneumonic::op::EOR}, - {op::INC, mneumonic::op::INC}, - {op::INX, mneumonic::op::INX}, - {op::INY, mneumonic::op::INY}, - {op::JMP, mneumonic::op::JMP}, - {op::JSR, mneumonic::op::JSR}, - {op::LDA, mneumonic::op::LDA}, - {op::LDX, mneumonic::op::LDX}, - {op::LDY, mneumonic::op::LDY}, - {op::LSR, mneumonic::op::LSR}, - {op::NOP, mneumonic::op::NOP}, - {op::ORA, mneumonic::op::ORA}, - {op::PHA, mneumonic::op::PHA}, - {op::PHP, mneumonic::op::PHP}, - {op::PHX, mneumonic::op::PHX}, - {op::PHY, mneumonic::op::PHY}, - {op::PLA, mneumonic::op::PLA}, - {op::PLP, mneumonic::op::PLP}, - {op::PLX, mneumonic::op::PLX}, - {op::PLY, mneumonic::op::PLY}, - {op::RMB0, mneumonic::op::RMB0}, - {op::RMB1, mneumonic::op::RMB1}, - {op::RMB2, mneumonic::op::RMB2}, - {op::RMB3, mneumonic::op::RMB3}, - {op::RMB4, mneumonic::op::RMB4}, - {op::RMB5, mneumonic::op::RMB5}, - {op::RMB6, mneumonic::op::RMB6}, - {op::RMB7, mneumonic::op::RMB7}, - {op::ROL, mneumonic::op::ROL}, - {op::ROR, mneumonic::op::ROR}, - {op::RTI, mneumonic::op::RTI}, - {op::RTS, mneumonic::op::RTS}, - {op::SBC, mneumonic::op::SBC}, - {op::SEC, mneumonic::op::SEC}, - {op::SED, mneumonic::op::SED}, - {op::SEI, mneumonic::op::SEI}, - {op::SMB0, mneumonic::op::SMB0}, - {op::SMB1, mneumonic::op::SMB1}, - {op::SMB2, mneumonic::op::SMB2}, - {op::SMB3, mneumonic::op::SMB3}, - {op::SMB4, mneumonic::op::SMB4}, - {op::SMB5, mneumonic::op::SMB5}, - {op::SMB6, mneumonic::op::SMB6}, - {op::SMB7, mneumonic::op::SMB7}, - {op::STA, mneumonic::op::STA}, - {op::STP, mneumonic::op::STP}, - {op::STX, mneumonic::op::STX}, - {op::STY, mneumonic::op::STY}, - {op::STZ, mneumonic::op::STZ}, - {op::TAX, mneumonic::op::TAX}, - {op::TAY, mneumonic::op::TAY}, - {op::TRB, mneumonic::op::TRB}, - {op::TSB, mneumonic::op::TSB}, - {op::TSX, mneumonic::op::TSX}, - {op::TXA, mneumonic::op::TXA}, - {op::TXS, mneumonic::op::TXS}, - {op::TYA, mneumonic::op::TYA}, - {op::WAI, mneumonic::op::WAI}, - }; + const std::unordered_map& op() { + static const std::unordered_map _ = { + {isa::op::ADC, mneumonic::op::ADC}, + {isa::op::AND, mneumonic::op::AND}, + {isa::op::ASL, mneumonic::op::ASL}, + {isa::op::BBR0, mneumonic::op::BBR0}, + {isa::op::BBR1, mneumonic::op::BBR1}, + {isa::op::BBR2, mneumonic::op::BBR2}, + {isa::op::BBR3, mneumonic::op::BBR3}, + {isa::op::BBR4, mneumonic::op::BBR4}, + {isa::op::BBR5, mneumonic::op::BBR5}, + {isa::op::BBR6, mneumonic::op::BBR6}, + {isa::op::BBR7, mneumonic::op::BBR7}, + {isa::op::BBS0, mneumonic::op::BBS0}, + {isa::op::BBS1, mneumonic::op::BBS1}, + {isa::op::BBS2, mneumonic::op::BBS2}, + {isa::op::BBS3, mneumonic::op::BBS3}, + {isa::op::BBS4, mneumonic::op::BBS4}, + {isa::op::BBS5, mneumonic::op::BBS5}, + {isa::op::BBS6, mneumonic::op::BBS6}, + {isa::op::BBS7, mneumonic::op::BBS7}, + {isa::op::BCC, mneumonic::op::BCC}, + {isa::op::BCS, mneumonic::op::BCS}, + {isa::op::BEQ, mneumonic::op::BEQ}, + {isa::op::BIT, mneumonic::op::BIT}, + {isa::op::BMI, mneumonic::op::BMI}, + {isa::op::BNE, mneumonic::op::BNE}, + {isa::op::BPL, mneumonic::op::BPL}, + {isa::op::BRA, mneumonic::op::BRA}, + {isa::op::BRK, mneumonic::op::BRK}, + {isa::op::BVC, mneumonic::op::BVC}, + {isa::op::BVS, mneumonic::op::BVS}, + {isa::op::CLC, mneumonic::op::CLC}, + {isa::op::CLD, mneumonic::op::CLD}, + {isa::op::CLI, mneumonic::op::CLI}, + {isa::op::CLV, mneumonic::op::CLV}, + {isa::op::CMP, mneumonic::op::CMP}, + {isa::op::CPX, mneumonic::op::CPX}, + {isa::op::CPY, mneumonic::op::CPY}, + {isa::op::DEC, mneumonic::op::DEC}, + {isa::op::DEX, mneumonic::op::DEX}, + {isa::op::DEY, mneumonic::op::DEY}, + {isa::op::EOR, mneumonic::op::EOR}, + {isa::op::INC, mneumonic::op::INC}, + {isa::op::INX, mneumonic::op::INX}, + {isa::op::INY, mneumonic::op::INY}, + {isa::op::JMP, mneumonic::op::JMP}, + {isa::op::JSR, mneumonic::op::JSR}, + {isa::op::LDA, mneumonic::op::LDA}, + {isa::op::LDX, mneumonic::op::LDX}, + {isa::op::LDY, mneumonic::op::LDY}, + {isa::op::LSR, mneumonic::op::LSR}, + {isa::op::NOP, mneumonic::op::NOP}, + {isa::op::ORA, mneumonic::op::ORA}, + {isa::op::PHA, mneumonic::op::PHA}, + {isa::op::PHP, mneumonic::op::PHP}, + {isa::op::PHX, mneumonic::op::PHX}, + {isa::op::PHY, mneumonic::op::PHY}, + {isa::op::PLA, mneumonic::op::PLA}, + {isa::op::PLP, mneumonic::op::PLP}, + {isa::op::PLX, mneumonic::op::PLX}, + {isa::op::PLY, mneumonic::op::PLY}, + {isa::op::RMB0, mneumonic::op::RMB0}, + {isa::op::RMB1, mneumonic::op::RMB1}, + {isa::op::RMB2, mneumonic::op::RMB2}, + {isa::op::RMB3, mneumonic::op::RMB3}, + {isa::op::RMB4, mneumonic::op::RMB4}, + {isa::op::RMB5, mneumonic::op::RMB5}, + {isa::op::RMB6, mneumonic::op::RMB6}, + {isa::op::RMB7, mneumonic::op::RMB7}, + {isa::op::ROL, mneumonic::op::ROL}, + {isa::op::ROR, mneumonic::op::ROR}, + {isa::op::RTI, mneumonic::op::RTI}, + {isa::op::RTS, mneumonic::op::RTS}, + {isa::op::SBC, mneumonic::op::SBC}, + {isa::op::SEC, mneumonic::op::SEC}, + {isa::op::SED, mneumonic::op::SED}, + {isa::op::SEI, mneumonic::op::SEI}, + {isa::op::SMB0, mneumonic::op::SMB0}, + {isa::op::SMB1, mneumonic::op::SMB1}, + {isa::op::SMB2, mneumonic::op::SMB2}, + {isa::op::SMB3, mneumonic::op::SMB3}, + {isa::op::SMB4, mneumonic::op::SMB4}, + {isa::op::SMB5, mneumonic::op::SMB5}, + {isa::op::SMB6, mneumonic::op::SMB6}, + {isa::op::SMB7, mneumonic::op::SMB7}, + {isa::op::STA, mneumonic::op::STA}, + {isa::op::STP, mneumonic::op::STP}, + {isa::op::STX, mneumonic::op::STX}, + {isa::op::STY, mneumonic::op::STY}, + {isa::op::STZ, mneumonic::op::STZ}, + {isa::op::TAX, mneumonic::op::TAX}, + {isa::op::TAY, mneumonic::op::TAY}, + {isa::op::TRB, mneumonic::op::TRB}, + {isa::op::TSB, mneumonic::op::TSB}, + {isa::op::TSX, mneumonic::op::TSX}, + {isa::op::TXA, mneumonic::op::TXA}, + {isa::op::TXS, mneumonic::op::TXS}, + {isa::op::TYA, mneumonic::op::TYA}, + {isa::op::WAI, mneumonic::op::WAI}, + }; + return _; + } - const std::unordered_map mode { - {mode::A, mneumonic::mode::A}, - {mode::AII, mneumonic::mode::AII}, - {mode::AIX, mneumonic::mode::AIX}, - {mode::AIY, mneumonic::mode::AIY}, - {mode::AI, mneumonic::mode::AI}, - {mode::ACC, mneumonic::mode::ACC}, - {mode::IMM, mneumonic::mode::IMM}, - {mode::I, mneumonic::mode::I}, - {mode::R, mneumonic::mode::R}, - {mode::S, mneumonic::mode::S}, - {mode::ZP, mneumonic::mode::ZP}, - {mode::ZPII, mneumonic::mode::ZPII}, - {mode::ZPX, mneumonic::mode::ZPX}, - {mode::ZPY, mneumonic::mode::ZPY}, - {mode::ZPI, mneumonic::mode::ZPI}, - {mode::ZPIY, mneumonic::mode::ZPIY}, - }; + const std::unordered_map& mode() { + static const std::unordered_map _ = { + {isa::mode::A, mneumonic::mode::A}, + {isa::mode::AII, mneumonic::mode::AII}, + {isa::mode::AIX, mneumonic::mode::AIX}, + {isa::mode::AIY, mneumonic::mode::AIY}, + {isa::mode::AI, mneumonic::mode::AI}, + {isa::mode::ACC, mneumonic::mode::ACC}, + {isa::mode::IMM, mneumonic::mode::IMM}, + {isa::mode::I, mneumonic::mode::I}, + {isa::mode::R, mneumonic::mode::R}, + {isa::mode::S, mneumonic::mode::S}, + {isa::mode::ZP, mneumonic::mode::ZP}, + {isa::mode::ZPII, mneumonic::mode::ZPII}, + {isa::mode::ZPX, mneumonic::mode::ZPX}, + {isa::mode::ZPY, mneumonic::mode::ZPY}, + {isa::mode::ZPI, mneumonic::mode::ZPI}, + {isa::mode::ZPIY, mneumonic::mode::ZPIY}, + }; + return _; + } } diff --git a/tostring.hh b/tostring.hh index a7200c0..2344264 100644 --- a/tostring.hh +++ b/tostring.hh @@ -5,7 +5,6 @@ #include "mneumonic.hh" namespace tostring { - extern const std::unordered_map op; - - extern const std::unordered_map mode; + const std::unordered_map& op(); + const std::unordered_map& mode(); }