1
0
mirror of https://github.com/lefticus/6502-cpp.git synced 2024-06-26 00:29:30 +00:00

Some reorg and start to move to ctre

This commit is contained in:
Jason Turner 2021-05-06 21:43:03 -06:00
parent 3f9fd79586
commit afcbe05bff
4 changed files with 307 additions and 319 deletions

View File

@ -1,5 +1,5 @@
--- ---
Checks: '*,-fuchsia-*,-google-*,-zircon-*,-abseil-*,-modernize-use-trailing-return-type,-llvm*' Checks: '*,-fuchsia-*,-google-*,-zircon-*,-abseil-*,-modernize-use-trailing-return-type,-llvm*,-altera*,-misc-non-private-member-variables-in-classes,-readability-else-after-return'
WarningsAsErrors: '*' WarningsAsErrors: '*'
HeaderFilterRegex: '' HeaderFilterRegex: ''
FormatStyle: none FormatStyle: none

View File

@ -14,6 +14,7 @@ macro(run_conan)
docopt.cpp/0.6.3 docopt.cpp/0.6.3
fmt/7.1.3 fmt/7.1.3
spdlog/1.8.5 spdlog/1.8.5
ctre/3.3.4
OPTIONS OPTIONS
${CONAN_EXTRA_OPTIONS} ${CONAN_EXTRA_OPTIONS}
BASIC_SETUP BASIC_SETUP

View File

@ -1,5 +1,7 @@
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
#include <ctre.hpp>
#include <fmt/format.h>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <map> #include <map>
@ -7,63 +9,6 @@
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include <fmt/format.h>
struct ASMLine
{
enum class Type {
Label,
Instruction,
Directive
};
ASMLine(Type t, std::string te) : type(t), text(std::move(te)) {}
Type type;
std::string text;
};
int parse_8bit_literal(const std::string &s)
{
return std::stoi(std::string(std::next(std::begin(s)), std::end(s)));
}
std::string strip_lo_hi(const std::string &s)
{
if ((s.starts_with("lo8(") || s.starts_with("hi8("))
&& s.ends_with(")")) {
return s.substr(4, s.size() - 5);
}
return s;
}
std::string fixup_8bit_literal(const std::string &s)
{
if (s[0] == '$') {
return "#" + std::to_string(static_cast<uint8_t>(parse_8bit_literal(s)));
}
if (s.starts_with("0x")) {
return "#$" + s.substr(2);
}
if (s.starts_with("lo8(") && s.ends_with(")")) {
return "#<" + strip_lo_hi(s);
}
if (s.starts_with("hi8(") && s.ends_with(")")) {
return "#>" + strip_lo_hi(s);
}
const auto is_num = std::all_of(begin(s), end(s), [](const auto c) { return (c >= '0' && c <= '9') || c == '-'; });
if (is_num) {
return "#<" + s;
}
return s;
}
struct Operand struct Operand
{ {
@ -87,7 +32,6 @@ struct Operand
Operand(const Type t, std::string v) Operand(const Type t, std::string v)
: type(t), value(std::move(v)) : type(t), value(std::move(v))
{ {
assert(type == Type::literal); assert(type == Type::literal);
} }
@ -98,6 +42,164 @@ struct Operand
} }
}; };
struct mos6502;
class Personality
{
public:
virtual void insert_autostart_sequence(std::vector<mos6502> &new_instructions) const = 0;
[[nodiscard]] virtual Operand get_register(const int reg_num) const = 0;
virtual ~Personality() = default;
Personality(const Personality &) = delete;
Personality(Personality &&) = delete;
Personality &operator=(const Personality &) = delete;
Personality &operator=(Personality &&) = delete;
protected:
Personality() = default;
};
struct ASMLine
{
enum class Type {
Label,
Instruction,
Directive
};
ASMLine(Type t, std::string te) : type(t), text(std::move(te)) {}
Type type;
std::string text;
};
struct C64 : Personality
{
void insert_autostart_sequence(std::vector<mos6502> &new_instructions) const override {
new_instructions.emplace_back(ASMLine::Type::Directive, "; jmp to start of program with BASIC");
new_instructions.emplace_back(ASMLine::Type::Directive, ".byt $0B,$08,$0A,$00,$9E,$32,$30,$36,$31,$00,$00,$00");
}
[[nodiscard]] Operand get_register(const int reg_num) const override
{
switch (reg_num) {
// http://sta.c64.org/cbm64mem.html
case 0:
return Operand(Operand::Type::literal, "$a7");// bit buffer for rs232
case 1:
return Operand(Operand::Type::literal, "$a8");// counter for rs232
case 2:
return Operand(Operand::Type::literal, "$05");// unused, int->fp routine pointer
case 3:
return Operand(Operand::Type::literal, "$06");
case 4:
return Operand(Operand::Type::literal, "$fb");// unused
case 5:
return Operand(Operand::Type::literal, "$fc");// unused
case 6:
return Operand(Operand::Type::literal, "$fd");// unused
case 7:
return Operand(Operand::Type::literal, "$fe");// unused
case 8:
return Operand(Operand::Type::literal, "$22");// unused
case 9:
return Operand(Operand::Type::literal, "$23");// unused
case 10:
return Operand(Operand::Type::literal, "$39");// Current BASIC line number
case 11:
return Operand(Operand::Type::literal, "$3a");// Current BASIC line number
case 12:
return Operand(Operand::Type::literal, "$61");// arithmetic register #1
case 13:
return Operand(Operand::Type::literal, "$62");
case 14:
return Operand(Operand::Type::literal, "$63");
case 15:
return Operand(Operand::Type::literal, "$64");
case 16:
return Operand(Operand::Type::literal, "$65");
case 17:
return Operand(Operand::Type::literal, "$69");// arithmetic register #2
case 18:
return Operand(Operand::Type::literal, "$6a");
case 19:
return Operand(Operand::Type::literal, "$6b");
case 20:
return Operand(Operand::Type::literal, "$6c");
case 21:
return Operand(Operand::Type::literal, "$6d");
case 22:
return Operand(Operand::Type::literal, "$57");// arithmetic register #3
case 23:
return Operand(Operand::Type::literal, "$58");
case 24:
return Operand(Operand::Type::literal, "$59");
case 25:
return Operand(Operand::Type::literal, "$5a");
case 26:
return Operand(Operand::Type::literal, "$5b");
case 27:
return Operand(Operand::Type::literal, "$5c");// arithmetic register #4
case 28:
return Operand(Operand::Type::literal, "$5d");
case 29:
return Operand(Operand::Type::literal, "$5e");
case 30:
return Operand(Operand::Type::literal, "$5f");
case 31:
return Operand(Operand::Type::literal, "$60");
}
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num));
}
};
int parse_8bit_literal(const std::string &s)
{
return std::stoi(std::string(std::next(std::begin(s)), std::end(s)));
}
std::string_view strip_lo_hi(std::string_view s)
{
const auto matcher = ctre::match<R"((lo|hi)8\((.*)\))">;
if (const auto results = matcher(s); results) {
return results.get<2>();
}
return s;
}
std::string fixup_8bit_literal(const std::string &s)
{
if (s[0] == '$') {
return "#" + std::to_string(static_cast<uint8_t>(parse_8bit_literal(s)));
}
if (s.starts_with("0x")) {
return "#$" + s.substr(2);
}
if (s.starts_with("lo8(")) {
return fmt::format("#<{}", strip_lo_hi(s));
}
if (s.starts_with("hi8(")) {
return fmt::format("#>{}", strip_lo_hi(s));
}
const auto is_num = std::all_of(begin(s), end(s), [](const auto c) { return (c >= '0' && c <= '9') || c == '-'; });
if (is_num) {
return "#<" + s;
}
return s;
}
struct mos6502 : ASMLine struct mos6502 : ASMLine
{ {
enum class OpCode { enum class OpCode {
@ -268,82 +370,44 @@ struct mos6502 : ASMLine
constexpr static std::string_view to_string(const OpCode o) constexpr static std::string_view to_string(const OpCode o)
{ {
switch (o) { switch (o) {
case OpCode::lda: case OpCode::lda: return "lda";
return "lda"; case OpCode::asl: return "asl";
case OpCode::asl: case OpCode::rol: return "rol";
return "asl"; case OpCode::ldy: return "ldy";
case OpCode::rol: case OpCode::tay: return "tay";
return "rol"; case OpCode::tya: return "tya";
case OpCode::ldy: case OpCode::tax: return "tax";
return "ldy"; case OpCode::txa: return "txa";
case OpCode::tay: case OpCode::cpy: return "cpy";
return "tay"; case OpCode::eor: return "eor";
case OpCode::tya: case OpCode::sta: return "sta";
return "tya"; case OpCode::sty: return "sty";
case OpCode::tax: case OpCode::pha: return "pha";
return "tax"; case OpCode::pla: return "pla";
case OpCode::txa: case OpCode::php: return "php";
return "txa"; case OpCode::plp: return "plp";
case OpCode::cpy: case OpCode::lsr: return "lsr";
return "cpy"; case OpCode::ror: return "ror";
case OpCode::eor: case OpCode::AND: return "and";
return "eor"; case OpCode::inc: return "inc";
case OpCode::sta: case OpCode::dec: return "dec";
return "sta"; case OpCode::ORA: return "ora";
case OpCode::sty: case OpCode::cmp: return "cmp";
return "sty"; case OpCode::bne: return "bne";
case OpCode::pha: case OpCode::bmi: return "bmi";
return "pha"; case OpCode::beq: return "beq";
case OpCode::pla: case OpCode::jmp: return "jmp";
return "pla"; case OpCode::adc: return "adc";
case OpCode::php: case OpCode::sbc: return "sbc";
return "php"; case OpCode::rts: return "rts";
case OpCode::plp: case OpCode::clc: return "clc";
return "plp"; case OpCode::sec: return "sec";
case OpCode::lsr: case OpCode::bit: return "bit";
return "lsr"; case OpCode::jsr: return "jsr";
case OpCode::ror: case OpCode::bpl: return "bpl";
return "ror"; case OpCode::bcc: return "bcc";
case OpCode::AND: case OpCode::bcs: return "bcs";
return "and"; case OpCode::unknown: return "";
case OpCode::inc:
return "inc";
case OpCode::dec:
return "dec";
case OpCode::ORA:
return "ora";
case OpCode::cmp:
return "cmp";
case OpCode::bne:
return "bne";
case OpCode::bmi:
return "bmi";
case OpCode::beq:
return "beq";
case OpCode::jmp:
return "jmp";
case OpCode::adc:
return "adc";
case OpCode::sbc:
return "sbc";
case OpCode::rts:
return "rts";
case OpCode::clc:
return "clc";
case OpCode::sec:
return "sec";
case OpCode::bit:
return "bit";
case OpCode::jsr:
return "jsr";
case OpCode::bpl:
return "bpl";
case OpCode::bcc:
return "bcc";
case OpCode::bcs:
return "bcs";
case OpCode::unknown:
return "";
} }
return ""; return "";
@ -356,10 +420,9 @@ struct mos6502 : ASMLine
return text;// + ':'; return text;// + ':';
case ASMLine::Type::Directive: case ASMLine::Type::Directive:
case ASMLine::Type::Instruction: { case ASMLine::Type::Instruction: {
const std::string line = '\t' + text + ' ' + op.value; return fmt::format("\t{} {:15}; {}", text, op.value, comment);
return line + std::string(static_cast<size_t>(std::max(15 - static_cast<int>(line.size()), 1)), ' ') + "; " + comment; }
} }
};
throw std::runtime_error("Unable to render: " + text); throw std::runtime_error("Unable to render: " + text);
} }
@ -433,35 +496,35 @@ struct AVR : ASMLine
if (o == "ret") { return OpCode::ret; } if (o == "ret") { return OpCode::ret; }
if (o == "mov") { return OpCode::mov; } if (o == "mov") { return OpCode::mov; }
if (o == "lsl") { return OpCode::lsl; } if (o == "lsl") { return OpCode::lsl; }
if (o == "rol") { return OpCode::rol;} if (o == "rol") { return OpCode::rol; }
if (o == "rcall") { return OpCode::rcall;} if (o == "rcall") { return OpCode::rcall; }
if (o == "ld") { return OpCode::ld;} if (o == "ld") { return OpCode::ld; }
if (o == "subi") { return OpCode::subi;} if (o == "subi") { return OpCode::subi; }
if (o == "sbci") { return OpCode::sbci;} if (o == "sbci") { return OpCode::sbci; }
if (o == "st") { return OpCode::st;} if (o == "st") { return OpCode::st; }
if (o == "lds") { return OpCode::lds;} if (o == "lds") { return OpCode::lds; }
if (o == "lsr") { return OpCode::lsr;} if (o == "lsr") { return OpCode::lsr; }
if (o == "andi") { return OpCode::andi;} if (o == "andi") { return OpCode::andi; }
if (o == "eor") { return OpCode::eor;} if (o == "eor") { return OpCode::eor; }
if (o == "sbrc") { return OpCode::sbrc;} if (o == "sbrc") { return OpCode::sbrc; }
if (o == "rjmp") { return OpCode::rjmp;} if (o == "rjmp") { return OpCode::rjmp; }
if (o == "sbrs") { return OpCode::sbrs;} if (o == "sbrs") { return OpCode::sbrs; }
if (o == "brne") { return OpCode::brne;} if (o == "brne") { return OpCode::brne; }
if (o == "dec") { return OpCode::dec;} if (o == "dec") { return OpCode::dec; }
if (o == "sbiw") { return OpCode::sbiw;} if (o == "sbiw") { return OpCode::sbiw; }
if (o == "push") { return OpCode::push;} if (o == "push") { return OpCode::push; }
if (o == "pop") { return OpCode::pop;} if (o == "pop") { return OpCode::pop; }
if (o == "com") { return OpCode::com;} if (o == "com") { return OpCode::com; }
if (o == "swap") { return OpCode::swap;} if (o == "swap") { return OpCode::swap; }
if (o == "clr") { return OpCode::clr;} if (o == "clr") { return OpCode::clr; }
if (o == "cpse") { return OpCode::cpse;} if (o == "cpse") { return OpCode::cpse; }
if (o == "cpi") { return OpCode::cpi;} if (o == "cpi") { return OpCode::cpi; }
if (o == "brlo") { return OpCode::brlo;} if (o == "brlo") { return OpCode::brlo; }
if (o == "add") { return OpCode::add;} if (o == "add") { return OpCode::add; }
if (o == "adc") { return OpCode::adc;} if (o == "adc") { return OpCode::adc; }
if (o == "cpc") { return OpCode::cpc;} if (o == "cpc") { return OpCode::cpc; }
if (o == "brsh") { return OpCode::brsh;} if (o == "brsh") { return OpCode::brsh; }
if (o == "breq") { return OpCode::breq;} if (o == "breq") { return OpCode::breq; }
} }
} }
throw std::runtime_error(fmt::format("Unknown opcode: {}")); throw std::runtime_error(fmt::format("Unknown opcode: {}"));
@ -482,84 +545,6 @@ struct AVR : ASMLine
throw std::runtime_error("Unknown register name"); throw std::runtime_error("Unknown register name");
} }
static Operand get_register(const char reg_name, const int byte = 0)
{
return get_register(get_register_number(reg_name), byte);
}
static Operand get_register(const int reg_num, [[maybe_unused]] const int offset = 0)
{
switch (reg_num) {
// http://sta.c64.org/cbm64mem.html
case 0:
return Operand(Operand::Type::literal, "$a7");// bit buffer for rs232
case 1:
return Operand(Operand::Type::literal, "$a8");// counter for rs232
case 2:
return Operand(Operand::Type::literal, "$05");// unused, int->fp routine pointer
case 3:
return Operand(Operand::Type::literal, "$06");
case 4:
return Operand(Operand::Type::literal, "$fb");// unused
case 5:
return Operand(Operand::Type::literal, "$fc");// unused
case 6:
return Operand(Operand::Type::literal, "$fd");// unused
case 7:
return Operand(Operand::Type::literal, "$fe");// unused
case 8:
return Operand(Operand::Type::literal, "$22");// unused
case 9:
return Operand(Operand::Type::literal, "$23");// unused
case 10:
return Operand(Operand::Type::literal, "$39");// Current BASIC line number
case 11:
return Operand(Operand::Type::literal, "$3a");// Current BASIC line number
case 12:
return Operand(Operand::Type::literal, "$61");// arithmetic register #1
case 13:
return Operand(Operand::Type::literal, "$62");
case 14:
return Operand(Operand::Type::literal, "$63");
case 15:
return Operand(Operand::Type::literal, "$64");
case 16:
return Operand(Operand::Type::literal, "$65");
case 17:
return Operand(Operand::Type::literal, "$69");// arithmetic register #2
case 18:
return Operand(Operand::Type::literal, "$6a");
case 19:
return Operand(Operand::Type::literal, "$6b");
case 20:
return Operand(Operand::Type::literal, "$6c");
case 21:
return Operand(Operand::Type::literal, "$6d");
case 22:
return Operand(Operand::Type::literal, "$57");// arithmetic register #3
case 23:
return Operand(Operand::Type::literal, "$58");
case 24:
return Operand(Operand::Type::literal, "$59");
case 25:
return Operand(Operand::Type::literal, "$5a");
case 26:
return Operand(Operand::Type::literal, "$5b");
case 27:
return Operand(Operand::Type::literal, "$5c");// arithmetic register #4
case 28:
return Operand(Operand::Type::literal, "$5d");
case 29:
return Operand(Operand::Type::literal, "$5e");
case 30:
return Operand(Operand::Type::literal, "$5f");
case 31:
return Operand(Operand::Type::literal, "$60");
}
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num));
}
static Operand parse_operand(std::string_view o) static Operand parse_operand(std::string_view o)
{ {
if (o.empty()) { if (o.empty()) {
@ -623,33 +608,33 @@ void fixup_16_bit_N_Z_flags(std::vector<mos6502> &instructions)
} }
void subtract_16_bit(std::vector<mos6502> &instructions, int reg, const std::uint16_t value) void subtract_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg, const std::uint16_t value)
{ {
//instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, address_low_byte)); //instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, address_low_byte));
instructions.emplace_back(mos6502::OpCode::sec); instructions.emplace_back(mos6502::OpCode::sec);
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(reg)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg));
instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string(value & 0xFF))); instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value & 0xFFu))));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(reg)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg));
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(reg + 1)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg + 1));
instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value >> 8) & 0xFF))); instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value >> 8u) & 0xFFu)));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(reg + 1)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1));
instructions.emplace_back(mos6502::OpCode::tax); instructions.emplace_back(mos6502::OpCode::tax);
fixup_16_bit_N_Z_flags(instructions); fixup_16_bit_N_Z_flags(instructions);
} }
void increment_16_bit(std::vector<mos6502> &instructions, int reg) void increment_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg)
{ {
//instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, address_low_byte)); //instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, address_low_byte));
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(reg)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg));
instructions.emplace_back(mos6502::OpCode::clc); instructions.emplace_back(mos6502::OpCode::clc);
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#1")); instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#1"));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(reg)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg));
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(reg + 1)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg + 1));
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#0")); instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#0"));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(reg + 1)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1));
} }
void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode op, const Operand &o1, const Operand &o2) void translate_instruction(const Personality &personality, std::vector<mos6502> &instructions, const AVR::OpCode op, const Operand &o1, const Operand &o2)
{ {
const auto translate_register_number = [](const Operand &reg) { const auto translate_register_number = [](const Operand &reg) {
if (reg.value == "__zero_reg__") { if (reg.value == "__zero_reg__") {
@ -666,40 +651,40 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
switch (op) { switch (op) {
case AVR::OpCode::dec: case AVR::OpCode::dec:
instructions.emplace_back(mos6502::OpCode::dec, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::dec, personality.get_register(o1_reg_num));
return; return;
case AVR::OpCode::ldi: case AVR::OpCode::ldi:
instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, fixup_8bit_literal(o2.value))); instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, fixup_8bit_literal(o2.value)));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
case AVR::OpCode::sts: case AVR::OpCode::sts:
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o2_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o2_reg_num));
instructions.emplace_back(mos6502::OpCode::sta, Operand(o1.type, o1.value)); instructions.emplace_back(mos6502::OpCode::sta, Operand(o1.type, o1.value));
return; return;
case AVR::OpCode::ret: case AVR::OpCode::ret:
instructions.emplace_back(mos6502::OpCode::rts); instructions.emplace_back(mos6502::OpCode::rts);
return; return;
case AVR::OpCode::mov: case AVR::OpCode::mov:
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o2_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o2_reg_num));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
case AVR::OpCode::lsl: case AVR::OpCode::lsl:
instructions.emplace_back(mos6502::OpCode::asl, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::asl, personality.get_register(o1_reg_num));
return; return;
case AVR::OpCode::rol: case AVR::OpCode::rol:
instructions.emplace_back(mos6502::OpCode::rol, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::rol, personality.get_register(o1_reg_num));
return; return;
case AVR::OpCode::rcall: case AVR::OpCode::rcall:
instructions.emplace_back(mos6502::OpCode::jsr, o1); instructions.emplace_back(mos6502::OpCode::jsr, o1);
return; return;
case AVR::OpCode::ld: { case AVR::OpCode::ld: {
if (o2.value == "Z" || o2.value == "X" || o2.value == "Y") { if (o2.value == "Z" || o2.value == "X" || o2.value == "Y") {
indirect_load(instructions, AVR::get_register(o2.value[0]).value, AVR::get_register(o1_reg_num).value); indirect_load(instructions, personality.get_register(o2.value[0]).value, personality.get_register(o1_reg_num).value);
return; return;
} }
if (o2.value == "Z+" || o2.value == "X+" || o2.value == "Y+") { if (o2.value == "Z+" || o2.value == "X+" || o2.value == "Y+") {
indirect_load(instructions, AVR::get_register(o2.value[0]).value, AVR::get_register(o1_reg_num).value); indirect_load(instructions, personality.get_register(o2.value[0]).value, personality.get_register(o1_reg_num).value);
increment_16_bit(instructions, AVR::get_register_number(o2.value[0])); increment_16_bit(personality, instructions, AVR::get_register_number(o2.value[0]));
return; return;
} }
throw std::runtime_error("Unhandled ld to non-Z"); throw std::runtime_error("Unhandled ld to non-Z");
@ -707,9 +692,9 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
case AVR::OpCode::sbci: { case AVR::OpCode::sbci: {
// we want to utilize the carry flag, however it was set previously // we want to utilize the carry flag, however it was set previously
// (it's really a borrow flag on the 6502) // (it's really a borrow flag on the 6502)
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::sbc, Operand(o2.type, fixup_8bit_literal(o2.value))); instructions.emplace_back(mos6502::OpCode::sbc, Operand(o2.type, fixup_8bit_literal(o2.value)));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
fixup_16_bit_N_Z_flags(instructions); fixup_16_bit_N_Z_flags(instructions);
return; return;
} }
@ -718,19 +703,19 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
// if |x| < |y| -> x-y +carry // if |x| < |y| -> x-y +carry
// for these special cases with -(1) and -(-(1)) // for these special cases with -(1) and -(-(1))
if (o2.value == "lo8(-(-1))") { if (o2.value == "lo8(-(-1))") {
instructions.emplace_back(mos6502::OpCode::dec, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::dec, personality.get_register(o1_reg_num));
return; return;
} }
if (o2.value == "lo8(-(1))") { if (o2.value == "lo8(-(1))") {
instructions.emplace_back(mos6502::OpCode::inc, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::inc, personality.get_register(o1_reg_num));
return; return;
} }
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
// have to set carry flag, since it gets inverted by sbc // have to set carry flag, since it gets inverted by sbc
instructions.emplace_back(mos6502::OpCode::sec); instructions.emplace_back(mos6502::OpCode::sec);
instructions.emplace_back(mos6502::OpCode::sbc, Operand(o2.type, fixup_8bit_literal(o2.value))); instructions.emplace_back(mos6502::OpCode::sbc, Operand(o2.type, fixup_8bit_literal(o2.value)));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
// temporarily store lower order (not carried substraction) byte into Y for checking // temporarily store lower order (not carried substraction) byte into Y for checking
// later if this is a two byte subtraction operation // later if this is a two byte subtraction operation
instructions.emplace_back(mos6502::OpCode::tax); instructions.emplace_back(mos6502::OpCode::tax);
@ -738,40 +723,40 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
} }
case AVR::OpCode::st: { case AVR::OpCode::st: {
if (o1.value == "Z" || o1.value == "Y" || o1.value == "X") { if (o1.value == "Z" || o1.value == "Y" || o1.value == "X") {
indirect_store(instructions, AVR::get_register(o2_reg_num).value, AVR::get_register(o1.value[0]).value); indirect_store(instructions, personality.get_register(o2_reg_num).value, personality.get_register(o1.value[0]).value);
return; return;
} }
if (o1.value == "Z+" || o1.value == "Y+" || o1.value == "X+") { if (o1.value == "Z+" || o1.value == "Y+" || o1.value == "X+") {
indirect_store(instructions, AVR::get_register(o2_reg_num).value, AVR::get_register(o1.value[0]).value); indirect_store(instructions, personality.get_register(o2_reg_num).value, personality.get_register(o1.value[0]).value);
increment_16_bit(instructions, AVR::get_register_number(o1.value[0])); increment_16_bit(personality, instructions, AVR::get_register_number(o1.value[0]));
return; return;
} }
throw std::runtime_error("Unhandled st"); throw std::runtime_error("Unhandled st");
} }
case AVR::OpCode::lds: { case AVR::OpCode::lds: {
instructions.emplace_back(mos6502::OpCode::lda, o2); instructions.emplace_back(mos6502::OpCode::lda, o2);
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::lsr: { case AVR::OpCode::lsr: {
instructions.emplace_back(mos6502::OpCode::lsr, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lsr, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::andi: { case AVR::OpCode::andi: {
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::AND, Operand(o2.type, fixup_8bit_literal(o2.value))); instructions.emplace_back(mos6502::OpCode::AND, Operand(o2.type, fixup_8bit_literal(o2.value)));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::eor: { case AVR::OpCode::eor: {
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::eor, AVR::get_register(o2_reg_num)); instructions.emplace_back(mos6502::OpCode::eor, personality.get_register(o2_reg_num));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::cpse: { case AVR::OpCode::cpse: {
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::bit, AVR::get_register(o2_reg_num)); instructions.emplace_back(mos6502::OpCode::bit, personality.get_register(o2_reg_num));
std::string new_label_name = "skip_next_instruction_" + std::to_string(instructions.size()); std::string new_label_name = "skip_next_instruction_" + std::to_string(instructions.size());
instructions.emplace_back(mos6502::OpCode::beq, Operand(Operand::Type::literal, new_label_name)); instructions.emplace_back(mos6502::OpCode::beq, Operand(Operand::Type::literal, new_label_name));
instructions.emplace_back(ASMLine::Type::Directive, new_label_name); instructions.emplace_back(ASMLine::Type::Directive, new_label_name);
@ -779,7 +764,7 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
} }
case AVR::OpCode::sbrc: { case AVR::OpCode::sbrc: {
instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, fixup_8bit_literal("$" + std::to_string(1 << (atoi(o2.value.c_str())))))); instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, fixup_8bit_literal("$" + std::to_string(1 << (atoi(o2.value.c_str()))))));
instructions.emplace_back(mos6502::OpCode::bit, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::bit, personality.get_register(o1_reg_num));
std::string new_label_name = "skip_next_instruction_" + std::to_string(instructions.size()); std::string new_label_name = "skip_next_instruction_" + std::to_string(instructions.size());
instructions.emplace_back(mos6502::OpCode::beq, Operand(Operand::Type::literal, new_label_name)); instructions.emplace_back(mos6502::OpCode::beq, Operand(Operand::Type::literal, new_label_name));
instructions.emplace_back(ASMLine::Type::Directive, new_label_name); instructions.emplace_back(ASMLine::Type::Directive, new_label_name);
@ -787,7 +772,7 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
} }
case AVR::OpCode::sbrs: { case AVR::OpCode::sbrs: {
instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, fixup_8bit_literal("$" + std::to_string(1 << (atoi(o2.value.c_str())))))); instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, fixup_8bit_literal("$" + std::to_string(1 << (atoi(o2.value.c_str()))))));
instructions.emplace_back(mos6502::OpCode::bit, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::bit, personality.get_register(o1_reg_num));
std::string new_label_name = "skip_next_instruction_" + std::to_string(instructions.size()); std::string new_label_name = "skip_next_instruction_" + std::to_string(instructions.size());
instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, new_label_name)); instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, new_label_name));
instructions.emplace_back(ASMLine::Type::Directive, new_label_name); instructions.emplace_back(ASMLine::Type::Directive, new_label_name);
@ -808,36 +793,36 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
} }
case AVR::OpCode::sbiw: { case AVR::OpCode::sbiw: {
subtract_16_bit(instructions, o1_reg_num, static_cast<std::uint16_t>(std::stoi(o2.value))); subtract_16_bit(personality, instructions, o1_reg_num, static_cast<std::uint16_t>(std::stoi(o2.value)));
return; return;
} }
case AVR::OpCode::push: { case AVR::OpCode::push: {
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::pha); instructions.emplace_back(mos6502::OpCode::pha);
return; return;
} }
case AVR::OpCode::pop: { case AVR::OpCode::pop: {
instructions.emplace_back(mos6502::OpCode::pla); instructions.emplace_back(mos6502::OpCode::pla);
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::com: { case AVR::OpCode::com: {
// We're doing this in the same way the AVR does it, to make sure the C flag is set properly // We're doing this in the same way the AVR does it, to make sure the C flag is set properly
instructions.emplace_back(mos6502::OpCode::clc); instructions.emplace_back(mos6502::OpCode::clc);
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$FF")); instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$FF"));
instructions.emplace_back(mos6502::OpCode::sbc, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sbc, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::clr: { case AVR::OpCode::clr: {
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$00")); instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$00"));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::cpi: { case AVR::OpCode::cpi: {
// note that this will leave the C flag in the 6502 borrow state, not normal carry state // note that this will leave the C flag in the 6502 borrow state, not normal carry state
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::cmp, Operand(o2.type, fixup_8bit_literal(o2.value))); instructions.emplace_back(mos6502::OpCode::cmp, Operand(o2.type, fixup_8bit_literal(o2.value)));
return; return;
} }
@ -863,28 +848,28 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
// ADC #$80 // ADC #$80
// ROL A // ROL A
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::asl); instructions.emplace_back(mos6502::OpCode::asl);
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#$80")); instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#$80"));
instructions.emplace_back(mos6502::OpCode::rol); instructions.emplace_back(mos6502::OpCode::rol);
instructions.emplace_back(mos6502::OpCode::asl); instructions.emplace_back(mos6502::OpCode::asl);
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#$80")); instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#$80"));
instructions.emplace_back(mos6502::OpCode::rol); instructions.emplace_back(mos6502::OpCode::rol);
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::add: { case AVR::OpCode::add: {
instructions.emplace_back(mos6502::OpCode::clc); instructions.emplace_back(mos6502::OpCode::clc);
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::adc, AVR::get_register(o2_reg_num)); instructions.emplace_back(mos6502::OpCode::adc, personality.get_register(o2_reg_num));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::adc: { case AVR::OpCode::adc: {
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::adc, AVR::get_register(o2_reg_num)); instructions.emplace_back(mos6502::OpCode::adc, personality.get_register(o2_reg_num));
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
return; return;
} }
case AVR::OpCode::cpc: { case AVR::OpCode::cpc: {
@ -893,8 +878,8 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
// the carry flag here, and assume that it's set how the 6502 wants it to be // the carry flag here, and assume that it's set how the 6502 wants it to be
// set from the previous operation // set from the previous operation
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
instructions.emplace_back(mos6502::OpCode::sbc, AVR::get_register(o2_reg_num)); instructions.emplace_back(mos6502::OpCode::sbc, personality.get_register(o2_reg_num));
return; return;
} }
case AVR::OpCode::brsh: { case AVR::OpCode::brsh: {
@ -949,7 +934,7 @@ void log(LogLevel ll, const std::size_t line_no, const std::string &line, const
std::cerr << to_string(ll) << ": " << line_no << ": " << message << ": `" << line << "`\n"; std::cerr << to_string(ll) << ": " << line_no << ": " << message << ": `" << line << "`\n";
} }
void to_mos6502(const AVR &from_instruction, std::vector<mos6502> &instructions) void to_mos6502(const Personality &personality, const AVR &from_instruction, std::vector<mos6502> &instructions)
{ {
try { try {
switch (from_instruction.type) { switch (from_instruction.type) {
@ -991,7 +976,7 @@ void to_mos6502(const AVR &from_instruction, std::vector<mos6502> &instructions)
const auto head = instructions.size(); const auto head = instructions.size();
try { try {
translate_instruction(instructions, from_instruction.opcode, from_instruction.operand1, from_instruction.operand2); translate_instruction(personality, instructions, from_instruction.opcode, from_instruction.operand1, from_instruction.operand2);
} catch (const std::exception &e) { } catch (const std::exception &e) {
instructions.emplace_back(ASMLine::Type::Directive, "; Unhandled opcode: '" + from_instruction.text + "' " + e.what()); instructions.emplace_back(ASMLine::Type::Directive, "; Unhandled opcode: '" + from_instruction.text + "' " + e.what());
log(LogLevel::Error, from_instruction, e.what()); log(LogLevel::Error, from_instruction, e.what());
@ -1224,7 +1209,7 @@ bool fix_overwritten_flags(std::vector<mos6502> &instructions)
return false; return false;
} }
void run(std::istream &input) void run(const Personality &personality, std::istream &input)
{ {
std::regex Comment(R"(\s*\#.*)"); std::regex Comment(R"(\s*\#.*)");
std::regex Label(R"(^\s*(\S+):.*)"); std::regex Label(R"(^\s*(\S+):.*)");
@ -1278,7 +1263,7 @@ void run(std::istream &input)
for (const auto &i : instructions) { for (const auto &i : instructions) {
if (i.type == ASMLine::Type::Instruction) { if (i.type == ASMLine::Type::Instruction) {
const auto check_label = [&](const auto &value) { const auto check_label = [&](const std::string &value) {
if (labels.count(value) != 0) { if (labels.count(value) != 0) {
used_labels.insert(value); used_labels.insert(value);
} }
@ -1286,8 +1271,8 @@ void run(std::istream &input)
check_label(i.operand1.value); check_label(i.operand1.value);
check_label(i.operand2.value); check_label(i.operand2.value);
check_label(strip_lo_hi(i.operand1.value)); check_label(std::string{ strip_lo_hi(i.operand1.value) });
check_label(strip_lo_hi(i.operand2.value)); check_label(std::string{ strip_lo_hi(i.operand2.value) });
} }
} }
@ -1321,7 +1306,7 @@ void run(std::istream &input)
if (i.operand2.value.starts_with("lo8(") || i.operand2.value.starts_with("hi8(")) { if (i.operand2.value.starts_with("lo8(") || i.operand2.value.starts_with("hi8(")) {
const auto potential_label = strip_lo_hi(i.operand2.value); const auto potential_label = strip_lo_hi(i.operand2.value);
const auto itr1 = new_labels.find(potential_label); const auto itr1 = new_labels.find(std::string{ potential_label });
if (itr1 != new_labels.end()) { if (itr1 != new_labels.end()) {
i.operand2.value.replace(4, potential_label.size(), itr1->second); i.operand2.value.replace(4, potential_label.size(), itr1->second);
} }
@ -1343,18 +1328,17 @@ void run(std::istream &input)
std::vector<mos6502> new_instructions; std::vector<mos6502> new_instructions;
new_instructions.emplace_back(ASMLine::Type::Directive, ".word " + std::to_string(start_address)); new_instructions.emplace_back(ASMLine::Type::Directive, ".word " + std::to_string(start_address));
new_instructions.emplace_back(ASMLine::Type::Directive, "* = " + std::to_string(start_address)); new_instructions.emplace_back(ASMLine::Type::Directive, "* = " + std::to_string(start_address));
new_instructions.emplace_back(ASMLine::Type::Directive, "; jmp to start of program with BASIC"); personality.insert_autostart_sequence(new_instructions);
new_instructions.emplace_back(ASMLine::Type::Directive, ".byt $0B,$08,$0A,$00,$9E,$32,$30,$36,$31,$00,$00,$00");
// set __zero_reg__ (reg 1 on AVR) to 0 // set __zero_reg__ (reg 1 on AVR) to 0
new_instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$00")); new_instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$00"));
new_instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(1)); new_instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(1));
new_instructions.emplace_back(mos6502::OpCode::jmp, Operand(Operand::Type::literal, "main")); new_instructions.emplace_back(mos6502::OpCode::jmp, Operand(Operand::Type::literal, "main"));
int instructions_to_skip = 0; int instructions_to_skip = 0;
std::string next_label_name; std::string next_label_name;
for (const auto &i : instructions) { for (const auto &i : instructions) {
to_mos6502(i, new_instructions); to_mos6502(personality, i, new_instructions);
// intentionally copy so we don't invalidate the reference // intentionally copy so we don't invalidate the reference
const auto last_instruction = new_instructions.back(); const auto last_instruction = new_instructions.back();
@ -1397,7 +1381,7 @@ void run(std::istream &input)
} }
} }
int main([[maybe_unused]] const int argc, const char *argv[]) int main(const int argc, const char **argv)
{ {
std::ifstream input_file; std::ifstream input_file;
@ -1410,6 +1394,8 @@ int main([[maybe_unused]] const int argc, const char *argv[])
} }
}(); }();
C64 personality;
std::cout << "; AVR Mode\n"; std::cout << "; AVR Mode\n";
run(input); run(personality, input);
} }

View File

@ -12,6 +12,7 @@ target_link_libraries(
6502-c++ 6502-c++
PRIVATE project_options PRIVATE project_options
project_warnings project_warnings
CONAN_PKG::ctre
CONAN_PKG::docopt.cpp CONAN_PKG::docopt.cpp
CONAN_PKG::fmt CONAN_PKG::fmt
CONAN_PKG::spdlog) CONAN_PKG::spdlog)