1
0
mirror of https://github.com/lefticus/6502-cpp.git synced 2024-12-21 10:30:35 +00:00

Almost working programs with AVR conversion

* need to add a decent header address
 * probably need to fix sbrc and sbrs
This commit is contained in:
Jason Turner 2021-04-22 15:52:35 -06:00
parent 13af1e8cca
commit 5591249f2a
3 changed files with 166 additions and 25 deletions

View File

@ -1,13 +1,11 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
set (CMAKE_CXX_STANDARD 14)
project(x86-to-6502) 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) 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 ()

View File

@ -6,22 +6,22 @@ enum class Colors : uint8_t
BLACK=0x00 BLACK=0x00
}; };
volatile uint8_t &memory_loc(const uint16_t loc) inline volatile uint8_t &memory_loc(const uint16_t loc)
{ {
return *reinterpret_cast<volatile uint8_t *>(loc); return *reinterpret_cast<volatile uint8_t *>(loc);
} }
void decrement_border_color() inline void decrement_border_color()
{ {
--memory_loc(0xd020); --memory_loc(0xd020);
} }
void increment_border_color() inline void increment_border_color()
{ {
++memory_loc(0xd020); ++memory_loc(0xd020);
} }
bool joystick_down() inline bool joystick_down()
{ {
uint8_t joystick_state = memory_loc(0xDC00); uint8_t joystick_state = memory_loc(0xDC00);
return (joystick_state & 0x2) == 0; return (joystick_state & 0x2) == 0;

View File

@ -34,6 +34,10 @@ std::string fixup_8bit_literal(const std::string &s)
{ {
return "#" + std::to_string(static_cast<uint8_t>(parse_8bit_literal(s))); return "#" + std::to_string(static_cast<uint8_t>(parse_8bit_literal(s)));
} else { } else {
if (s.starts_with("lo8(") && s.ends_with(")")) {
return "#<" + s.substr(4, s.size() - 5);
}
return s; return s;
} }
} }
@ -60,6 +64,7 @@ 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);
} }
@ -76,6 +81,8 @@ struct mos6502 : ASMLine
{ {
unknown, unknown,
lda, lda,
asl,
rol,
ldy, ldy,
tay, tay,
tya, tya,
@ -140,6 +147,8 @@ struct mos6502 : ASMLine
case OpCode::clc: case OpCode::clc:
case OpCode::sec: case OpCode::sec:
case OpCode::bit: case OpCode::bit:
case OpCode::asl:
case OpCode::rol:
case OpCode::unknown: case OpCode::unknown:
break; break;
} }
@ -179,6 +188,8 @@ struct mos6502 : ASMLine
case OpCode::rts: case OpCode::rts:
case OpCode::clc: case OpCode::clc:
case OpCode::sec: case OpCode::sec:
case OpCode::rol:
case OpCode::asl:
case OpCode::unknown: case OpCode::unknown:
break; break;
} }
@ -206,6 +217,10 @@ struct mos6502 : ASMLine
switch (o) { switch (o) {
case OpCode::lda: case OpCode::lda:
return "lda"; return "lda";
case OpCode::asl:
return "asl";
case OpCode::rol:
return "rol";
case OpCode::ldy: case OpCode::ldy:
return "ldy"; return "ldy";
case OpCode::tay: case OpCode::tay:
@ -482,7 +497,21 @@ struct AVR : ASMLine
unknown, unknown,
ldi, ldi,
sts, 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) static OpCode parse_opcode(Type t, const std::string &o)
@ -495,9 +524,23 @@ struct AVR : ASMLine
return OpCode::unknown; return OpCode::unknown;
case Type::Instruction: 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 == "sts") return OpCode::sts;
if (o == "ret") return OpCode::ret; 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); 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 29: return Operand(Operand::Type::literal, "$5e");
case 30: return Operand(Operand::Type::literal, "$5f"); case 30: return Operand(Operand::Type::literal, "$5f");
case 31: return Operand(Operand::Type::literal, "$60"); case 31: return Operand(Operand::Type::literal, "$60");
}; }
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num)); 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<mos6502> &instructions, const AVR::OpCode op, const Operand &o1, const Operand &o2) void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode op, const Operand &o1, const Operand &o2)
{ {
std::cout << "; translating avr instruction : " << static_cast<int>(op) << '\n';
switch(op) switch(op)
{ {
case AVR::OpCode::ldi: 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)); instructions.emplace_back(mos6502::OpCode::sta, AVR::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, 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; 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:
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"); 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<typename FromArch> template<typename FromArch>
void to_mos6502(const FromArch &i, std::vector<mos6502> &instructions) void to_mos6502(const FromArch &i, std::vector<mos6502> &instructions)
{ {
std::cout << "; arch " << typeid(FromArch).name() << '\n';
try { try {
switch(i.type) switch(i.type)
{ {
@ -916,8 +1049,6 @@ void to_mos6502(const FromArch &i, std::vector<mos6502> &instructions)
instructions.emplace_back(i.type, i.text); instructions.emplace_back(i.type, i.text);
return; return;
case ASMLine::Type::Instruction: case ASMLine::Type::Instruction:
instructions.emplace_back(ASMLine::Type::Directive, "; " + i.line_text);
const auto head = instructions.size(); const auto head = instructions.size();
try { try {
@ -1104,7 +1235,6 @@ void run(std::istream &input) {
{ {
std::string line; std::string line;
getline(input, line); getline(input, line);
std::cout << "; read line: '" << line << "'\n";
try { try {
std::smatch match; std::smatch match;
if (std::regex_match(line, match, Label)) if (std::regex_match(line, match, Label))
@ -1132,12 +1262,8 @@ void run(std::istream &input) {
++lineno; ++lineno;
} }
std::cout << "; done reading file" << std::endl;
std::set<std::string> labels; std::set<std::string> labels;
std::cout << "; " << instructions.size() << " instructions parsed" << std::endl;
for (const auto &i : instructions) for (const auto &i : instructions)
{ {
if (i.type == ASMLine::Type::Label) { if (i.type == ASMLine::Type::Label) {
@ -1212,10 +1338,27 @@ void run(std::istream &input) {
std::vector<mos6502> new_instructions; std::vector<mos6502> new_instructions;
bool skip_next_instruction = false;
std::string next_label_name;
for (const auto &i : instructions) for (const auto &i : instructions)
{ {
std::cout << "; translating instruction: '" << i.text << '\'' << std::endl;
to_mos6502(i, new_instructions); 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<std::ptrdiff_t>(last_instruction_loc)));
}
} }
while (fix_overwritten_flags(new_instructions)) while (fix_overwritten_flags(new_instructions))