diff --git a/CMakeLists.txt b/CMakeLists.txt index 0040ab1..bfd5a5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,11 @@ cmake_minimum_required(VERSION 3.5) -set (CMAKE_CXX_STANDARD 14) - project(x86-to-6502) -if(CMAKE_COMPILER_IS_GNUCC) - add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic -std=c++14) -endif() - add_executable(x86-to-6502 src/main.cpp) +target_compile_features(x86-to-6502 PRIVATE cxx_std_20) +if (CMAKE_COMPILER_IS_GNUCC) + target_compile_options(x86-to-6502 PRIVATE -Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wpedantic) +endif () diff --git a/examples/test2.cpp b/examples/test2.cpp index 2001fc1..744e29b 100644 --- a/examples/test2.cpp +++ b/examples/test2.cpp @@ -6,22 +6,22 @@ enum class Colors : uint8_t BLACK=0x00 }; -volatile uint8_t &memory_loc(const uint16_t loc) +inline volatile uint8_t &memory_loc(const uint16_t loc) { return *reinterpret_cast(loc); } -void decrement_border_color() +inline void decrement_border_color() { --memory_loc(0xd020); } -void increment_border_color() +inline void increment_border_color() { ++memory_loc(0xd020); } -bool joystick_down() +inline bool joystick_down() { uint8_t joystick_state = memory_loc(0xDC00); return (joystick_state & 0x2) == 0; diff --git a/src/main.cpp b/src/main.cpp index 958d0ab..5b1fd1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,6 +34,10 @@ std::string fixup_8bit_literal(const std::string &s) { return "#" + std::to_string(static_cast(parse_8bit_literal(s))); } else { + if (s.starts_with("lo8(") && s.ends_with(")")) { + return "#<" + s.substr(4, s.size() - 5); + } + return s; } } @@ -60,6 +64,7 @@ struct Operand Operand(const Type t, std::string v) : type(t), value(std::move(v)) { + assert(type == Type::literal); } @@ -76,6 +81,8 @@ struct mos6502 : ASMLine { unknown, lda, + asl, + rol, ldy, tay, tya, @@ -140,6 +147,8 @@ struct mos6502 : ASMLine case OpCode::clc: case OpCode::sec: case OpCode::bit: + case OpCode::asl: + case OpCode::rol: case OpCode::unknown: break; } @@ -179,6 +188,8 @@ struct mos6502 : ASMLine case OpCode::rts: case OpCode::clc: case OpCode::sec: + case OpCode::rol: + case OpCode::asl: case OpCode::unknown: break; } @@ -206,6 +217,10 @@ struct mos6502 : ASMLine 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: @@ -482,7 +497,21 @@ struct AVR : ASMLine unknown, ldi, sts, - ret + ret, + mov, + lsl, + rol, + rcall, + ld, + subi, + st, + lds, + lsr, + andi, + eor, + sbrc, + sbrs, + rjmp }; static OpCode parse_opcode(Type t, const std::string &o) @@ -495,9 +524,23 @@ struct AVR : ASMLine return OpCode::unknown; case Type::Instruction: { - if (o == "ldi") { std::cout << "; parsed ldi\n"; return OpCode::ldi; } + if (o == "ldi") return OpCode::ldi; if (o == "sts") return OpCode::sts; 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 == "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; } } throw std::runtime_error("Unknown opcode: " + o); @@ -538,7 +581,7 @@ static Operand get_register(const int reg_num, [[maybe_unused]] const int offset 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)); } @@ -571,20 +614,111 @@ static Operand get_register(const int reg_num, [[maybe_unused]] const int offset void translate_instruction(std::vector &instructions, const AVR::OpCode op, const Operand &o1, const Operand &o2) { - std::cout << "; translating avr instruction : " << static_cast(op) << '\n'; switch(op) { case AVR::OpCode::ldi: - instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, 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)); return; case AVR::OpCode::sts: instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o2.reg_num)); - instructions.emplace_back(mos6502::OpCode::sta, Operand(o2.type, o2.value)); + 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)); + return; + case AVR::OpCode::lsl: + instructions.emplace_back(mos6502::OpCode::asl, AVR::get_register(o1.reg_num)); + return; + case AVR::OpCode::rol: + instructions.emplace_back(mos6502::OpCode::rol, AVR::get_register(o1.reg_num)); + return; + case AVR::OpCode::rcall: + instructions.emplace_back(mos6502::OpCode::jsr, Operand(o1.type, o1.value)); + return; + case AVR::OpCode::ld: + { + if (o2.value == "Z") { + instructions.emplace_back(mos6502::OpCode::ldy, Operand(Operand::Type::literal, "#0")); + instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, + "(" + AVR::get_register(30).value + "), Y")); + instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1.reg_num)); + return; + } + throw std::runtime_error("Unhandled ld to non-Z"); + } + case AVR::OpCode::subi: + { + // to do: deal with Carry bit (and other flags) nonsense from AVR + // 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)); + return; + } + if (o2.value == "lo8(-(1))") { + instructions.emplace_back(mos6502::OpCode::inc, AVR::get_register(o1.reg_num)); + return; + } + + throw std::runtime_error("Unhandled subi sub case"); + } + case AVR::OpCode::st: { + if (o1.value == "Z") { + instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o2.reg_num)); + instructions.emplace_back(mos6502::OpCode::ldy, Operand(Operand::Type::literal, "#0")); + instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, + "(" + AVR::get_register(30).value + "), Y")); + + return; + } + throw std::runtime_error("Unhandled st with non-Z parameter"); + } + case AVR::OpCode::lds: { + instructions.emplace_back(mos6502::OpCode::lda, o2); + instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1.reg_num)); + return; + } + case AVR::OpCode::lsr: { + instructions.emplace_back(mos6502::OpCode::lsr, AVR::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::AND, Operand(o2.type, fixup_8bit_literal(o2.value))); + instructions.emplace_back(mos6502::OpCode::sta, AVR::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)); + return; + } + 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())-1))))); + instructions.emplace_back(mos6502::OpCode::bit, AVR::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); + return; + } + 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())-1))))); + instructions.emplace_back(mos6502::OpCode::bit, AVR::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); + return; + } + case AVR::OpCode::rjmp: { + instructions.emplace_back(mos6502::OpCode::jmp, o1); + return; + } } throw std::runtime_error("Could not translate unhandled instruction"); @@ -905,7 +1039,6 @@ void log(LogLevel ll, const int line_no, const std::string &line, const std::str template void to_mos6502(const FromArch &i, std::vector &instructions) { - std::cout << "; arch " << typeid(FromArch).name() << '\n'; try { switch(i.type) { @@ -916,8 +1049,6 @@ void to_mos6502(const FromArch &i, std::vector &instructions) instructions.emplace_back(i.type, i.text); return; case ASMLine::Type::Instruction: - instructions.emplace_back(ASMLine::Type::Directive, "; " + i.line_text); - const auto head = instructions.size(); try { @@ -1104,7 +1235,6 @@ void run(std::istream &input) { { std::string line; getline(input, line); - std::cout << "; read line: '" << line << "'\n"; try { std::smatch match; if (std::regex_match(line, match, Label)) @@ -1132,12 +1262,8 @@ void run(std::istream &input) { ++lineno; } - std::cout << "; done reading file" << std::endl; - std::set labels; - std::cout << "; " << instructions.size() << " instructions parsed" << std::endl; - for (const auto &i : instructions) { if (i.type == ASMLine::Type::Label) { @@ -1212,10 +1338,27 @@ void run(std::istream &input) { std::vector new_instructions; + bool skip_next_instruction = false; + std::string next_label_name; for (const auto &i : instructions) { - std::cout << "; translating instruction: '" << i.text << '\'' << std::endl; to_mos6502(i, new_instructions); + + // intentionally copy so we don't invalidate the reference + const auto last_instruction = new_instructions.back(); + const auto last_instruction_loc = new_instructions.size() - 1; + + if (skip_next_instruction) { + new_instructions.emplace_back(ASMLine::Type::Label, next_label_name); + skip_next_instruction = false; + } + + if (last_instruction.type == ASMLine::Type::Directive && last_instruction.text.starts_with("skip_next_instruction")) + { + skip_next_instruction = true; + next_label_name = last_instruction.text; + new_instructions.erase(std::next(new_instructions.begin(), static_cast(last_instruction_loc))); + } } while (fix_overwritten_flags(new_instructions))