diff --git a/.clang-format b/.clang-format index 6ab2738..a5f381d 100644 --- a/.clang-format +++ b/.clang-format @@ -1,7 +1,7 @@ AccessModifierOffset: -2 AlignAfterOpenBracket: DontAlign -AlignConsecutiveAssignments: None -AlignConsecutiveDeclarations: Consecutive +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: false @@ -79,7 +79,7 @@ ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: false PointerAlignment: Right ReflowComments: true -SortIncludes: CaseInsensitive +SortIncludes: true SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: false diff --git a/include/personalities/c64.hpp b/include/personalities/c64.hpp index 1aa0151..d8e109e 100644 --- a/include/personalities/c64.hpp +++ b/include/personalities/c64.hpp @@ -21,38 +21,38 @@ struct C64 : Personality { 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"); + case 0: return Operand(Operand::Type::literal, "$4e");// unused, int->fp routine pointer + case 1: return Operand(Operand::Type::literal, "$4f"); + case 2: return Operand(Operand::Type::literal, "$50");// unused + case 3: return Operand(Operand::Type::literal, "$51");// unused + case 4: return Operand(Operand::Type::literal, "$52");// bit buffer for rs232 + case 5: return Operand(Operand::Type::literal, "$53");// counter for rs232 + case 6: return Operand(Operand::Type::literal, "$54");// unused + case 7: return Operand(Operand::Type::literal, "$55");// unused + case 8: return Operand(Operand::Type::literal, "$56");// unused + case 9: return Operand(Operand::Type::literal, "$57");// unused + case 10: return Operand(Operand::Type::literal, "$58");// Current BASIC line number + case 11: return Operand(Operand::Type::literal, "$59");// Current BASIC line number + case 12: return Operand(Operand::Type::literal, "$5a");// arithmetic register #3 + case 13: return Operand(Operand::Type::literal, "$5b"); + case 14: return Operand(Operand::Type::literal, "$5c"); + case 15: return Operand(Operand::Type::literal, "$5d"); + case 16: return Operand(Operand::Type::literal, "$5e"); + case 17: return Operand(Operand::Type::literal, "$5f"); + case 18: return Operand(Operand::Type::literal, "$60"); + case 19: return Operand(Operand::Type::literal, "$61"); + case 20: return Operand(Operand::Type::literal, "$62"); + case 21: return Operand(Operand::Type::literal, "$63"); + case 22: return Operand(Operand::Type::literal, "$64"); + case 23: return Operand(Operand::Type::literal, "$65"); + case 24: return Operand(Operand::Type::literal, "$66"); + case 25: return Operand(Operand::Type::literal, "$67"); + case 26: return Operand(Operand::Type::literal, "$68"); + case 27: return Operand(Operand::Type::literal, "$69"); + case 28: return Operand(Operand::Type::literal, "$6a"); + case 29: return Operand(Operand::Type::literal, "$6b"); + case 30: return Operand(Operand::Type::literal, "$6c"); + case 31: return Operand(Operand::Type::literal, "$6d"); } throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num)); } diff --git a/src/6502-c++.cpp b/src/6502-c++.cpp index c054c99..1bcda7a 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -48,6 +48,17 @@ std::string_view strip_negate(std::string_view s) } +std::string_view strip_offset(std::string_view s) +{ + const auto matcher = ctre::match; + + if (const auto results = matcher(s); results) { return results.get<1>(); } + + return s; +} + + + std::string fixup_8bit_literal(const std::string &s) { if (s[0] == '$') { return "#" + std::to_string(static_cast(parse_8bit_literal(s))); } @@ -92,6 +103,8 @@ struct AVR : ASMLine eor, in, + inc, + icall, ld, ldd, @@ -140,6 +153,7 @@ struct AVR : ASMLine if (o == "rol") { return OpCode::rol; } if (o == "ror") { return OpCode::ror; } if (o == "rcall") { return OpCode::rcall; } + if (o == "icall") { return OpCode::icall; } if (o == "call") { return OpCode::call; } if (o == "ld") { return OpCode::ld; } if (o == "sub") { return OpCode::sub; } @@ -176,6 +190,7 @@ struct AVR : ASMLine if (o == "breq") { return OpCode::breq; } if (o == "in") { return OpCode::in; } if (o == "out") { return OpCode::out; } + if (o == "inc") { return OpCode::inc; } } } throw std::runtime_error(fmt::format("Unknown opcode: {}", o)); @@ -251,7 +266,7 @@ void fixup_16_bit_N_Z_flags(std::vector &instructions) instructions.emplace_back(mos6502::OpCode::bmi, Operand(Operand::Type::literal, set_flag_label)); // if it's not 0, then branch down, we know the result is not 0 and not negative instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, set_flag_label)); - // if the higher order byte is 0, test the lower order byte, which was saved for us in Y + // if the higher order byte is 0, test the lower order byte, which was saved for us in X instructions.emplace_back(mos6502::OpCode::txa); // if low order is not negative, we know it's 0 or not 0 instructions.emplace_back(mos6502::OpCode::bpl, Operand(Operand::Type::literal, set_flag_label)); @@ -351,6 +366,17 @@ void translate_instruction(const Personality &personality, return; } throw std::runtime_error("Unhandled call"); + case AVR::OpCode::icall: + { + std::string new_label_name = "return_from_icall_" + std::to_string(instructions.size()); + instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, fmt::format("#>({}-1)", new_label_name))); + instructions.emplace_back(mos6502::OpCode::pha); + instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, fmt::format("#<({}-1)", new_label_name))); + instructions.emplace_back(mos6502::OpCode::pha); + instructions.emplace_back(mos6502::OpCode::jmp, Operand(Operand::Type::literal, "(" + personality.get_register(AVR::get_register_number('Z')).value + ")")); + instructions.emplace_back(ASMLine::Type::Label, new_label_name); + return; + } case AVR::OpCode::rcall: if (o1.value != ".") { instructions.emplace_back(mos6502::OpCode::jsr, o1); @@ -426,6 +452,10 @@ void translate_instruction(const Personality &personality, fixup_16_bit_N_Z_flags(instructions); return; } + case AVR::OpCode::inc: + instructions.emplace_back(mos6502::OpCode::inc, personality.get_register(o1_reg_num)); + return; + case AVR::OpCode::subi: { // to do: deal with Carry bit (and other flags) nonsense from AVR // if |x| < |y| -> x-y +carry @@ -719,8 +749,19 @@ void to_mos6502(const Personality &personality, const AVR &from_instruction, std case ASMLine::Type::Directive: if (from_instruction.text.starts_with(".string")) { instructions.emplace_back(ASMLine::Type::Directive, ".asc " + from_instruction.text.substr(7)); + } else if (from_instruction.text.starts_with(".word")) { + + const auto matcher = ctre::match; + + if (const auto results = matcher(from_instruction.text); results) { + const auto matched_gs = results.get<1>().to_string(); + instructions.emplace_back(ASMLine::Type::Directive, ".word " + matched_gs); + } else { + spdlog::warn("Unknown .word directive"); + } + } else if (from_instruction.text.starts_with(".byte")) { - instructions.emplace_back(ASMLine::Type::Directive, ".byt " + from_instruction.text.substr(5)); + instructions.emplace_back(ASMLine::Type::Directive, ".byt <" + from_instruction.text.substr(6)); } else if (from_instruction.text.starts_with(".zero")) { const auto count = std::stoull(&*std::next(from_instruction.text.begin(), 6), nullptr, 10); @@ -866,16 +907,24 @@ std::vector run(const Personality &personality, std::istream &input) std::set used_labels{ "main", "__udivmodhi4", "__mulhi3" }; for (const auto &i : instructions) { - if (i.type == ASMLine::Type::Instruction) { + const auto check_label = [&](const std::string &value) { + if (labels.count(value) != 0) { used_labels.insert(value); } + }; - const auto check_label = [&](const std::string &value) { - if (labels.count(value) != 0) { used_labels.insert(value); } - }; + if (i.type == ASMLine::Type::Instruction) { check_label(i.operand1.value); check_label(i.operand2.value); - check_label(std::string{ strip_negate(strip_lo_hi(i.operand1.value)) }); - check_label(std::string{ strip_negate(strip_lo_hi(i.operand2.value)) }); + check_label(std::string{ strip_offset(strip_negate(strip_lo_hi(i.operand1.value))) }); + check_label(std::string{ strip_offset(strip_negate(strip_lo_hi(i.operand2.value))) }); + } else if (i.type == ASMLine::Type::Directive) { + const auto matcher = ctre::match; + + if (const auto results = matcher(i.text); results) { + const auto matched_gs = results.get<1>().to_string(); + spdlog::trace("matched gs: '{}' from '{}'", matched_gs, i.text); + check_label(matched_gs); + } } } @@ -963,9 +1012,9 @@ std::vector run(const Personality &personality, std::istream &input) } } - while (optimize(new_instructions, personality)) { +// while (optimize(new_instructions, personality)) { // do it however many times it takes - } +// } int branch_patch_count = 0; while (fix_long_branches(new_instructions, branch_patch_count)) { @@ -979,6 +1028,7 @@ enum struct Target { C64 }; int main(const int argc, const char **argv) { + spdlog::set_level(spdlog::level::trace); const std::map targets{ { "C64", Target::C64 } }; CLI::App app{ "C++ Compiler for 6502 processors" }; @@ -1009,7 +1059,7 @@ int main(const int argc, const char **argv) const std::string gcc_command = fmt::format( "avr-gcc -fverbose-asm -c -o {outfile} -S {warning_flags} -std=c++20 -mtiny-stack " - "-mmcu={avr} -O{optimization} {include_dirs} {infile}", + "-mmcu={avr} -O{optimization} -fno-tree-loop-vectorize {include_dirs} {infile}", fmt::arg("outfile", avr_output_file.generic_string()), fmt::arg("warning_flags", warning_flags), fmt::arg("avr", avr),