From baf9c092eaeaf1ff35393b9d3428cd2e9b41f81f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 8 May 2021 21:15:21 -0600 Subject: [PATCH] Add some (broken) stack handling. Need to move to -mtiny-stack --- include/personalities/c64.hpp | 9 +++ src/6502-c++.cpp | 104 +++++++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 27 deletions(-) diff --git a/include/personalities/c64.hpp b/include/personalities/c64.hpp index 2379222..bd52036 100644 --- a/include/personalities/c64.hpp +++ b/include/personalities/c64.hpp @@ -15,6 +15,12 @@ struct C64 : Personality 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"); + + // load start of stack space into stack address pointers + new_instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$FF")); + new_instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, std::string{stack_low_address()})); + new_instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$CF")); + new_instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, std::string{ stack_high_address() })); } [[nodiscard]] std::string_view stack_low_address() const override @@ -94,6 +100,9 @@ struct C64 : Personality return Operand(Operand::Type::literal, "$5f"); case 31: return Operand(Operand::Type::literal, "$60"); + case 32: + // 32 is the "Stack Pointer", because I decided so, I mean, it makes sense + return Operand(Operand::Type::literal, std::string{stack_low_address()}); } 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 6dd1dbf..e9fa100 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,18 +8,18 @@ #include #include #include +#include #include #include -#include -#include -#include "../include/assembly.hpp" #include "../include/6502.hpp" +#include "../include/assembly.hpp" #include "../include/optimizer.hpp" #include "../include/personalities/c64.hpp" -int to_int(const std::string_view sv) { +int to_int(const std::string_view sv) +{ int result{}; std::from_chars(sv.begin(), sv.end(), result); return result; @@ -31,7 +32,7 @@ int parse_8bit_literal(const std::string_view s) std::string_view strip_lo_hi(std::string_view s) { - const auto matcher = ctre::match; + const auto matcher = ctre::match; if (const auto results = matcher(s); results) { return results.get<2>(); @@ -40,6 +41,18 @@ std::string_view strip_lo_hi(std::string_view s) return s; } +std::string_view strip_negate(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] == '$') { @@ -67,7 +80,6 @@ std::string fixup_8bit_literal(const std::string &s) } - struct AVR : ASMLine { enum class OpCode { @@ -140,9 +152,9 @@ struct AVR : ASMLine if (o == "rol") { return OpCode::rol; } if (o == "rcall") { return OpCode::rcall; } if (o == "ld") { return OpCode::ld; } - if (o == "sub") { return OpCode::subi; } + if (o == "sub") { return OpCode::sub; } if (o == "subi") { return OpCode::subi; } - if (o == "sbc") { return OpCode::sbci; } + if (o == "sbc") { return OpCode::sbc; } if (o == "sbci") { return OpCode::sbci; } if (o == "st") { return OpCode::st; } if (o == "std") { return OpCode::std; } @@ -336,7 +348,10 @@ void translate_instruction(const Personality &personality, std::vector instructions.emplace_back(mos6502::OpCode::rol, personality.get_register(o1_reg_num)); return; case AVR::OpCode::rcall: - instructions.emplace_back(mos6502::OpCode::jsr, o1); + if (o1.value != ".") { + instructions.emplace_back(mos6502::OpCode::jsr, o1); + } + return; case AVR::OpCode::ld: { if (o2.value == "Z" || o2.value == "X" || o2.value == "Y") { @@ -351,12 +366,20 @@ void translate_instruction(const Personality &personality, std::vector throw std::runtime_error("Unknown ld indexing"); } case AVR::OpCode::ldd: { - indirect_load(instructions, personality.get_register(AVR::get_register_number(o2.value[0])).value, personality.get_register(o1_reg_num).value, to_int(o2.value.substr(1))); - return; + if (o2.value[1] == '+') { + indirect_load(instructions, personality.get_register(AVR::get_register_number(o2.value[0])).value, personality.get_register(o1_reg_num).value, to_int(o2.value.substr(2))); + return; + } + + throw std::runtime_error("Unhandled 'ldd'"); } case AVR::OpCode::std: { - indirect_store(instructions, personality.get_register(o2_reg_num).value, personality.get_register(AVR::get_register_number(o1.value[0])).value, to_int(o2.value.substr(1))); - return; + if (o1.value[1] == '+') { + indirect_store(instructions, personality.get_register(o2_reg_num).value, personality.get_register(AVR::get_register_number(o1.value[0])).value, to_int(o1.value.substr(2))); + return; + } + + throw std::runtime_error("Unhandled 'std'"); } case AVR::OpCode::sub: { // we want to utilize the carry flag, however it was set previously @@ -469,10 +492,19 @@ void translate_instruction(const Personality &personality, std::vector case AVR::OpCode::brne: { if (o1.value == "0b") { instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, "memcpy_0")); + return; + } else if (o1.value == ".+2") { + // assumes 6502 'borrow' for Carry flag instead of carry, so bcc instead of bcs + 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); + return; } else { instructions.emplace_back(mos6502::OpCode::bne, o1); + return; } - return; + + throw std::runtime_error("Unhanled brne format"); } case AVR::OpCode::rjmp: { @@ -597,14 +629,14 @@ void translate_instruction(const Personality &personality, std::vector case AVR::OpCode::in: { if (o2.value == "__SP_L__") { - instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, std::string{personality.stack_low_address()})); - instructions.emplace_back(mos6502::OpCode::sta, o1); + instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, std::string{ personality.stack_low_address() })); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } if (o2.value == "__SP_H__") { instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, std::string{ personality.stack_high_address() })); - instructions.emplace_back(mos6502::OpCode::sta, o1); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } @@ -612,8 +644,17 @@ void translate_instruction(const Personality &personality, std::vector } case AVR::OpCode::breq: { - instructions.emplace_back(mos6502::OpCode::beq, o1); - return; + if (o1.value == ".+2") + { + // assumes 6502 'borrow' for Carry flag instead of carry, so bcc instead of bcs + 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); + return; + } else { + instructions.emplace_back(mos6502::OpCode::beq, o1); + return; + } } case AVR::OpCode::unknown: { throw std::runtime_error("Could not translate 'unknown' instruction"); @@ -637,6 +678,8 @@ 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(".byte")) { + instructions.emplace_back(ASMLine::Type::Directive, ".byt " + from_instruction.text.substr(5)); } else if (from_instruction.text.starts_with(".zero")) { const auto count = std::stoull(&*std::next(from_instruction.text.begin(), 6), nullptr, 10); @@ -826,8 +869,8 @@ void run(const Personality &personality, std::istream &input) check_label(i.operand1.value); check_label(i.operand2.value); - check_label(std::string{ strip_lo_hi(i.operand1.value) }); - check_label(std::string{ strip_lo_hi(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)) }); } } @@ -835,16 +878,23 @@ void run(const Personality &personality, std::istream &input) [&used_labels]() { std::map result; for (const auto &l : used_labels) { - auto newl = l; - std::transform(newl.begin(), newl.end(), newl.begin(), [](const auto c) { return std::tolower(c); }); - newl.erase(std::remove_if(newl.begin(), newl.end(), [](const auto c) { return !std::isalnum(c); }), std::end(newl)); +// auto newl = l; +// std::transform(newl.begin(), newl.end(), newl.begin(), [](const auto c) { return std::tolower(c); }); +// newl.erase(std::remove_if(newl.begin(), newl.end(), [](const auto c) { return !std::isalnum(c); }), std::end(newl)); - result.emplace(std::make_pair(l, newl)); + // strip just first \. + if (l[0] == '.') { + result.emplace(std::make_pair(l, l.substr(1))); + } else { + result.emplace(std::make_pair(l, l)); + } } return result; }(); - + for (const auto &label : new_labels) { + spdlog::trace("used label: '{}':'{}'", label.first, label.second); + } for (auto &i : instructions) { if (i.type == ASMLine::Type::Label) { @@ -883,7 +933,7 @@ void run(const Personality &personality, std::istream &input) std::vector new_instructions; personality.insert_autostart_sequence(new_instructions); - // 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::sta, personality.get_register(1)); new_instructions.emplace_back(mos6502::OpCode::jmp, Operand(Operand::Type::literal, "main"));