From afcbe05bff6f23e48c5770ec9ddc72fae7802177 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 6 May 2021 21:43:03 -0600 Subject: [PATCH] Some reorg and start to move to ctre --- .clang-tidy | 2 +- cmake/Conan.cmake | 1 + src/6502-c++.cpp | 622 ++++++++++++++++++++++----------------------- src/CMakeLists.txt | 1 + 4 files changed, 307 insertions(+), 319 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index f95f74f..4db910d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -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: '*' HeaderFilterRegex: '' FormatStyle: none diff --git a/cmake/Conan.cmake b/cmake/Conan.cmake index a514b15..d885b50 100644 --- a/cmake/Conan.cmake +++ b/cmake/Conan.cmake @@ -14,6 +14,7 @@ macro(run_conan) docopt.cpp/0.6.3 fmt/7.1.3 spdlog/1.8.5 + ctre/3.3.4 OPTIONS ${CONAN_EXTRA_OPTIONS} BASIC_SETUP diff --git a/src/6502-c++.cpp b/src/6502-c++.cpp index d49b362..28a64b4 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include @@ -7,63 +9,6 @@ #include #include #include -#include - -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(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 { @@ -87,7 +32,6 @@ struct Operand Operand(const Type t, std::string v) : type(t), value(std::move(v)) { - assert(type == Type::literal); } @@ -98,6 +42,164 @@ struct Operand } }; +struct mos6502; + +class Personality +{ +public: + virtual void insert_autostart_sequence(std::vector &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 &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; + + 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(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 { enum class OpCode { @@ -268,82 +370,44 @@ struct mos6502 : ASMLine constexpr static std::string_view to_string(const OpCode o) { switch (o) { - case OpCode::lda: - return "lda"; - case OpCode::asl: - return "asl"; - case OpCode::rol: - return "rol"; - case OpCode::ldy: - return "ldy"; - case OpCode::tay: - return "tay"; - case OpCode::tya: - return "tya"; - case OpCode::tax: - return "tax"; - case OpCode::txa: - return "txa"; - case OpCode::cpy: - return "cpy"; - case OpCode::eor: - return "eor"; - case OpCode::sta: - return "sta"; - case OpCode::sty: - return "sty"; - case OpCode::pha: - return "pha"; - case OpCode::pla: - return "pla"; - case OpCode::php: - return "php"; - case OpCode::plp: - return "plp"; - case OpCode::lsr: - return "lsr"; - case OpCode::ror: - return "ror"; - case OpCode::AND: - return "and"; - 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 ""; + case OpCode::lda: return "lda"; + case OpCode::asl: return "asl"; + case OpCode::rol: return "rol"; + case OpCode::ldy: return "ldy"; + case OpCode::tay: return "tay"; + case OpCode::tya: return "tya"; + case OpCode::tax: return "tax"; + case OpCode::txa: return "txa"; + case OpCode::cpy: return "cpy"; + case OpCode::eor: return "eor"; + case OpCode::sta: return "sta"; + case OpCode::sty: return "sty"; + case OpCode::pha: return "pha"; + case OpCode::pla: return "pla"; + case OpCode::php: return "php"; + case OpCode::plp: return "plp"; + case OpCode::lsr: return "lsr"; + case OpCode::ror: return "ror"; + case OpCode::AND: return "and"; + 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 ""; @@ -356,10 +420,9 @@ struct mos6502 : ASMLine return text;// + ':'; case ASMLine::Type::Directive: case ASMLine::Type::Instruction: { - const std::string line = '\t' + text + ' ' + op.value; - return line + std::string(static_cast(std::max(15 - static_cast(line.size()), 1)), ' ') + "; " + comment; + return fmt::format("\t{} {:15}; {}", text, op.value, comment); + } } - }; throw std::runtime_error("Unable to render: " + text); } @@ -433,35 +496,35 @@ struct AVR : ASMLine if (o == "ret") { return OpCode::ret; } if (o == "mov") { return OpCode::mov; } if (o == "lsl") { return OpCode::lsl; } - if (o == "rol") { return OpCode::rol;} - if (o == "rcall") { return OpCode::rcall;} - if (o == "ld") { return OpCode::ld;} - if (o == "subi") { return OpCode::subi;} - if (o == "sbci") { return OpCode::sbci;} - if (o == "st") { return OpCode::st;} - if (o == "lds") { return OpCode::lds;} - if (o == "lsr") { return OpCode::lsr;} - if (o == "andi") { return OpCode::andi;} - if (o == "eor") { return OpCode::eor;} - if (o == "sbrc") { return OpCode::sbrc;} - if (o == "rjmp") { return OpCode::rjmp;} - if (o == "sbrs") { return OpCode::sbrs;} - if (o == "brne") { return OpCode::brne;} - if (o == "dec") { return OpCode::dec;} - if (o == "sbiw") { return OpCode::sbiw;} - if (o == "push") { return OpCode::push;} - if (o == "pop") { return OpCode::pop;} - if (o == "com") { return OpCode::com;} - if (o == "swap") { return OpCode::swap;} - if (o == "clr") { return OpCode::clr;} - if (o == "cpse") { return OpCode::cpse;} - if (o == "cpi") { return OpCode::cpi;} - if (o == "brlo") { return OpCode::brlo;} - if (o == "add") { return OpCode::add;} - if (o == "adc") { return OpCode::adc;} - if (o == "cpc") { return OpCode::cpc;} - if (o == "brsh") { return OpCode::brsh;} - if (o == "breq") { return OpCode::breq;} + if (o == "rol") { return OpCode::rol; } + if (o == "rcall") { return OpCode::rcall; } + if (o == "ld") { return OpCode::ld; } + if (o == "subi") { return OpCode::subi; } + if (o == "sbci") { return OpCode::sbci; } + if (o == "st") { return OpCode::st; } + if (o == "lds") { return OpCode::lds; } + if (o == "lsr") { return OpCode::lsr; } + if (o == "andi") { return OpCode::andi; } + if (o == "eor") { return OpCode::eor; } + if (o == "sbrc") { return OpCode::sbrc; } + if (o == "rjmp") { return OpCode::rjmp; } + if (o == "sbrs") { return OpCode::sbrs; } + if (o == "brne") { return OpCode::brne; } + if (o == "dec") { return OpCode::dec; } + if (o == "sbiw") { return OpCode::sbiw; } + if (o == "push") { return OpCode::push; } + if (o == "pop") { return OpCode::pop; } + if (o == "com") { return OpCode::com; } + if (o == "swap") { return OpCode::swap; } + if (o == "clr") { return OpCode::clr; } + if (o == "cpse") { return OpCode::cpse; } + if (o == "cpi") { return OpCode::cpi; } + if (o == "brlo") { return OpCode::brlo; } + if (o == "add") { return OpCode::add; } + if (o == "adc") { return OpCode::adc; } + if (o == "cpc") { return OpCode::cpc; } + if (o == "brsh") { return OpCode::brsh; } + if (o == "breq") { return OpCode::breq; } } } throw std::runtime_error(fmt::format("Unknown opcode: {}")); @@ -482,84 +545,6 @@ struct AVR : ASMLine 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) { if (o.empty()) { @@ -623,33 +608,33 @@ void fixup_16_bit_N_Z_flags(std::vector &instructions) } -void subtract_16_bit(std::vector &instructions, int reg, const std::uint16_t value) +void subtract_16_bit(const Personality &personality, std::vector &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::sec); - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(reg)); - instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string(value & 0xFF))); - instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(reg)); - instructions.emplace_back(mos6502::OpCode::lda, AVR::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::sta, AVR::get_register(reg + 1)); + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg)); + instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value & 0xFFu)))); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg)); + 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 >> 8u) & 0xFFu))); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1)); instructions.emplace_back(mos6502::OpCode::tax); fixup_16_bit_N_Z_flags(instructions); } -void increment_16_bit(std::vector &instructions, int reg) +void increment_16_bit(const Personality &personality, std::vector &instructions, int reg) { //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::adc, Operand(Operand::Type::literal, "#1")); - instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(reg)); - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(reg + 1)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg)); + 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::sta, AVR::get_register(reg + 1)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1)); } -void translate_instruction(std::vector &instructions, const AVR::OpCode op, const Operand &o1, const Operand &o2) +void translate_instruction(const Personality &personality, std::vector &instructions, const AVR::OpCode op, const Operand &o1, const Operand &o2) { const auto translate_register_number = [](const Operand ®) { if (reg.value == "__zero_reg__") { @@ -666,40 +651,40 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode switch (op) { 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; case AVR::OpCode::ldi: 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; 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)); return; case AVR::OpCode::ret: instructions.emplace_back(mos6502::OpCode::rts); return; case AVR::OpCode::mov: - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o2_reg_num)); - instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o2_reg_num)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; 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; 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; case AVR::OpCode::rcall: instructions.emplace_back(mos6502::OpCode::jsr, o1); return; case AVR::OpCode::ld: { 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; } 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); - increment_16_bit(instructions, AVR::get_register_number(o2.value[0])); + indirect_load(instructions, personality.get_register(o2.value[0]).value, personality.get_register(o1_reg_num).value); + increment_16_bit(personality, instructions, AVR::get_register_number(o2.value[0])); return; } throw std::runtime_error("Unhandled ld to non-Z"); @@ -707,9 +692,9 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode case AVR::OpCode::sbci: { // we want to utilize the carry flag, however it was set previously // (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::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); return; } @@ -718,19 +703,19 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode // if |x| < |y| -> x-y +carry // for these special cases with -(1) and -(-(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; } 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; } - 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 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::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 // later if this is a two byte subtraction operation instructions.emplace_back(mos6502::OpCode::tax); @@ -738,40 +723,40 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode } case AVR::OpCode::st: { 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; } 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); - increment_16_bit(instructions, AVR::get_register_number(o1.value[0])); + indirect_store(instructions, personality.get_register(o2_reg_num).value, personality.get_register(o1.value[0]).value); + increment_16_bit(personality, instructions, AVR::get_register_number(o1.value[0])); return; } throw std::runtime_error("Unhandled st"); } case AVR::OpCode::lds: { 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; } 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; } 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::sta, AVR::get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } case AVR::OpCode::eor: { - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); - instructions.emplace_back(mos6502::OpCode::eor, AVR::get_register(o2_reg_num)); - instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::eor, personality.get_register(o2_reg_num)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } case AVR::OpCode::cpse: { - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); - instructions.emplace_back(mos6502::OpCode::bit, AVR::get_register(o2_reg_num)); + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_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()); instructions.emplace_back(mos6502::OpCode::beq, Operand(Operand::Type::literal, new_label_name)); instructions.emplace_back(ASMLine::Type::Directive, new_label_name); @@ -779,7 +764,7 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode } 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::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()); instructions.emplace_back(mos6502::OpCode::beq, Operand(Operand::Type::literal, new_label_name)); instructions.emplace_back(ASMLine::Type::Directive, new_label_name); @@ -787,7 +772,7 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode } 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::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()); instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, new_label_name)); instructions.emplace_back(ASMLine::Type::Directive, new_label_name); @@ -808,36 +793,36 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode } case AVR::OpCode::sbiw: { - subtract_16_bit(instructions, o1_reg_num, static_cast(std::stoi(o2.value))); + subtract_16_bit(personality, instructions, o1_reg_num, static_cast(std::stoi(o2.value))); return; } 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); return; } case AVR::OpCode::pop: { 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; } 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 instructions.emplace_back(mos6502::OpCode::clc); 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::sta, AVR::get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::sbc, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } case AVR::OpCode::clr: { 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; } case AVR::OpCode::cpi: { // 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))); return; } @@ -863,28 +848,28 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode // ADC #$80 // 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::adc, Operand(Operand::Type::literal, "#$80")); instructions.emplace_back(mos6502::OpCode::rol); instructions.emplace_back(mos6502::OpCode::asl); instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#$80")); 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; } case AVR::OpCode::add: { instructions.emplace_back(mos6502::OpCode::clc); - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); - instructions.emplace_back(mos6502::OpCode::adc, AVR::get_register(o2_reg_num)); - instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::adc, personality.get_register(o2_reg_num)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } case AVR::OpCode::adc: { - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); - instructions.emplace_back(mos6502::OpCode::adc, AVR::get_register(o2_reg_num)); - instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::adc, personality.get_register(o2_reg_num)); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } case AVR::OpCode::cpc: { @@ -893,8 +878,8 @@ void translate_instruction(std::vector &instructions, const AVR::OpCode // the carry flag here, and assume that it's set how the 6502 wants it to be // set from the previous operation - instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num)); - instructions.emplace_back(mos6502::OpCode::sbc, AVR::get_register(o2_reg_num)); + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::sbc, personality.get_register(o2_reg_num)); return; } 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"; } -void to_mos6502(const AVR &from_instruction, std::vector &instructions) +void to_mos6502(const Personality &personality, const AVR &from_instruction, std::vector &instructions) { try { switch (from_instruction.type) { @@ -991,7 +976,7 @@ void to_mos6502(const AVR &from_instruction, std::vector &instructions) const auto head = instructions.size(); 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) { instructions.emplace_back(ASMLine::Type::Directive, "; Unhandled opcode: '" + from_instruction.text + "' " + e.what()); log(LogLevel::Error, from_instruction, e.what()); @@ -1224,7 +1209,7 @@ bool fix_overwritten_flags(std::vector &instructions) return false; } -void run(std::istream &input) +void run(const Personality &personality, std::istream &input) { std::regex Comment(R"(\s*\#.*)"); std::regex Label(R"(^\s*(\S+):.*)"); @@ -1278,7 +1263,7 @@ void run(std::istream &input) for (const auto &i : instructions) { 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) { used_labels.insert(value); } @@ -1286,8 +1271,8 @@ void run(std::istream &input) check_label(i.operand1.value); check_label(i.operand2.value); - check_label(strip_lo_hi(i.operand1.value)); - check_label(strip_lo_hi(i.operand2.value)); + check_label(std::string{ strip_lo_hi(i.operand1.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(")) { 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()) { i.operand2.value.replace(4, potential_label.size(), itr1->second); } @@ -1343,18 +1328,17 @@ void run(std::istream &input) std::vector new_instructions; 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, "; 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"); - // set __zero_reg__ (reg 1 on AVR) to 0 + personality.insert_autostart_sequence(new_instructions); + // 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::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")); int instructions_to_skip = 0; std::string next_label_name; 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 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; @@ -1410,6 +1394,8 @@ int main([[maybe_unused]] const int argc, const char *argv[]) } }(); + C64 personality; + std::cout << "; AVR Mode\n"; - run(input); + run(personality, input); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4cec0fe..c097665 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries( 6502-c++ PRIVATE project_options project_warnings + CONAN_PKG::ctre CONAN_PKG::docopt.cpp CONAN_PKG::fmt CONAN_PKG::spdlog)