add support for linking multiple programs + binaries

This commit is contained in:
Zack Buhman 2022-04-05 03:10:13 -07:00
parent b60dbed70b
commit 210a8d1b06
10 changed files with 382 additions and 262 deletions

View File

@ -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

View File

@ -3,6 +3,8 @@
#include <optional>
#include <variant>
#include <vector>
#include <memory>
#include <unordered_map>
#include "isa.hh"
@ -24,7 +26,27 @@ namespace assembler {
isa::mode mode;
std::variant<literal_t, reference_t, implied_t> value;
size_t location;
ssize_t row; // debug
};
using program_t = std::vector<instruction_t>;
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<std::string> buf;
};
using program_t = std::vector<std::variant<instruction_t, blob_t>>;
struct symbol_strings_t {
size_t current_symbol;
std::unordered_map<std::string, size_t> map;
};
using symbol_table_t = std::unordered_map<size_t, size_t>;
}

View File

@ -10,7 +10,7 @@ namespace codec {
const std::map<std::tuple<isa::op, isa::mode>, uint8_t>& encode() {
static const std::map<std::tuple<isa::op, isa::mode>, 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<uint8_t, std::tuple<isa::op, isa::mode>>& decode() {
static const std::map<uint8_t, std::tuple<isa::op, isa::mode>> _ = {
{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}},

164
main.cc
View File

@ -2,83 +2,69 @@
#include <fstream>
#include <iostream>
#include <unordered_map>
#include <memory>
#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<size_t, assembler::program_t::const_iterator>;
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<assembler::reference_t>(ins->value)) {
assembler::reference_t ref = std::get<assembler::reference_t>(ins->value);
if (std::holds_alternative<assembler::reference_t>(ins.value)) {
assembler::reference_t ref = std::get<assembler::reference_t>(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<ssize_t>(ref_ins->location) - static_cast<ssize_t>(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<ssize_t>(ref_location) - static_cast<ssize_t>(ins.location + 2);
return offset;
} else {
return ref_ins->location + link_location;
return ref_location;
}
} else if (std::holds_alternative<assembler::literal_t>(ins->value)) {
assembler::literal_t lit = std::get<assembler::literal_t>(ins->value);
} else if (std::holds_alternative<assembler::literal_t>(ins.value)) {
assembler::literal_t lit = std::get<assembler::literal_t>(ins.value);
return lit.num;
} else if (std::holds_alternative<assembler::implied_t>(ins->value)) {
assert (std::holds_alternative<assembler::implied_t>(ins->value));
} else if (std::holds_alternative<assembler::implied_t>(ins.value)) {
//assert (std::holds_alternative<assembler::implied_t>(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<assembler::instruction_t>(*prog_it)) {
auto ins = std::get<assembler::instruction_t>(*prog_it);
serialize_instruction(ins);
} else if (std::holds_alternative<assembler::blob_t>(*prog_it)) {
auto blob = std::get<assembler::blob_t>(*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<std::string>(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;

View File

@ -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<bool(std::string_view, ssize_t, ssize_t)> cb)
{
@ -68,30 +69,14 @@ namespace parser {
};
}
using symbol_strings_t = std::unordered_map<std::string_view, size_t>;
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<int>(op_it->second) << "`\n";
//std::cerr << row << ": ok op `" << static_cast<int>(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<int>(mode_it->second) << "`\n";
//std::cerr << "ok mode `" << static_cast<int>(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<ssize_t> {
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;
}
}

View File

@ -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);
}

63
symbol.cc Normal file
View File

@ -0,0 +1,63 @@
#include <string_view>
#include <cassert>
#include <iostream>
#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<assembler::instruction_t>(*prog_it)) {
auto& ins = std::get<assembler::instruction_t>(*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<assembler::blob_t>(*prog_it)) {
auto& blob = std::get<assembler::blob_t>(*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;
}
}

11
symbol.hh Normal file
View File

@ -0,0 +1,11 @@
#include <string_view>
#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);
}

View File

@ -1,127 +1,133 @@
#include <map>
#include <unordered_map>
#include <string>
#include "instruction.hh"
#include "isa.hh"
#include "mneumonic.hh"
namespace tostring {
const std::unordered_map<op_t, std::string_view> 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<isa::op, std::string_view>& op() {
static const std::unordered_map<isa::op, std::string_view> _ = {
{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<amode_t, std::string_view> 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<isa::mode, std::string_view>& mode() {
static const std::unordered_map<isa::mode, std::string_view> _ = {
{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 _;
}
}

View File

@ -5,7 +5,6 @@
#include "mneumonic.hh"
namespace tostring {
extern const std::unordered_map<op_t, std::string_view> op;
extern const std::unordered_map<amode_t, std::string_view> mode;
const std::unordered_map<isa::op, std::string_view>& op();
const std::unordered_map<isa::mode, std::string_view>& mode();
}