mirror of
https://github.com/lefticus/6502-cpp.git
synced 2024-12-21 10:30:35 +00:00
Add icall, inc, and fix up some assembly parsing
This commit is contained in:
parent
e7a3db9dda
commit
ac8895120f
@ -1,7 +1,7 @@
|
|||||||
AccessModifierOffset: -2
|
AccessModifierOffset: -2
|
||||||
AlignAfterOpenBracket: DontAlign
|
AlignAfterOpenBracket: DontAlign
|
||||||
AlignConsecutiveAssignments: None
|
AlignConsecutiveAssignments: false
|
||||||
AlignConsecutiveDeclarations: Consecutive
|
AlignConsecutiveDeclarations: false
|
||||||
AlignEscapedNewlines: Left
|
AlignEscapedNewlines: Left
|
||||||
AlignOperands: true
|
AlignOperands: true
|
||||||
AlignTrailingComments: false
|
AlignTrailingComments: false
|
||||||
@ -79,7 +79,7 @@ ObjCSpaceAfterProperty: true
|
|||||||
ObjCSpaceBeforeProtocolList: false
|
ObjCSpaceBeforeProtocolList: false
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ReflowComments: true
|
ReflowComments: true
|
||||||
SortIncludes: CaseInsensitive
|
SortIncludes: true
|
||||||
SortUsingDeclarations: false
|
SortUsingDeclarations: false
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: false
|
||||||
SpaceAfterTemplateKeyword: false
|
SpaceAfterTemplateKeyword: false
|
||||||
|
@ -21,38 +21,38 @@ struct C64 : Personality
|
|||||||
{
|
{
|
||||||
switch (reg_num) {
|
switch (reg_num) {
|
||||||
// http://sta.c64.org/cbm64mem.html
|
// http://sta.c64.org/cbm64mem.html
|
||||||
case 0: return Operand(Operand::Type::literal, "$a7");// bit buffer for rs232
|
case 0: return Operand(Operand::Type::literal, "$4e");// unused, int->fp routine pointer
|
||||||
case 1: return Operand(Operand::Type::literal, "$a8");// counter for rs232
|
case 1: return Operand(Operand::Type::literal, "$4f");
|
||||||
case 2: return Operand(Operand::Type::literal, "$05");// unused, int->fp routine pointer
|
case 2: return Operand(Operand::Type::literal, "$50");// unused
|
||||||
case 3: return Operand(Operand::Type::literal, "$06");
|
case 3: return Operand(Operand::Type::literal, "$51");// unused
|
||||||
case 4: return Operand(Operand::Type::literal, "$fb");// unused
|
case 4: return Operand(Operand::Type::literal, "$52");// bit buffer for rs232
|
||||||
case 5: return Operand(Operand::Type::literal, "$fc");// unused
|
case 5: return Operand(Operand::Type::literal, "$53");// counter for rs232
|
||||||
case 6: return Operand(Operand::Type::literal, "$fd");// unused
|
case 6: return Operand(Operand::Type::literal, "$54");// unused
|
||||||
case 7: return Operand(Operand::Type::literal, "$fe");// unused
|
case 7: return Operand(Operand::Type::literal, "$55");// unused
|
||||||
case 8: return Operand(Operand::Type::literal, "$22");// unused
|
case 8: return Operand(Operand::Type::literal, "$56");// unused
|
||||||
case 9: return Operand(Operand::Type::literal, "$23");// unused
|
case 9: return Operand(Operand::Type::literal, "$57");// unused
|
||||||
case 10: return Operand(Operand::Type::literal, "$39");// Current BASIC line number
|
case 10: return Operand(Operand::Type::literal, "$58");// Current BASIC line number
|
||||||
case 11: return Operand(Operand::Type::literal, "$3a");// Current BASIC line number
|
case 11: return Operand(Operand::Type::literal, "$59");// Current BASIC line number
|
||||||
case 12: return Operand(Operand::Type::literal, "$61");// arithmetic register #1
|
case 12: return Operand(Operand::Type::literal, "$5a");// arithmetic register #3
|
||||||
case 13: return Operand(Operand::Type::literal, "$62");
|
case 13: return Operand(Operand::Type::literal, "$5b");
|
||||||
case 14: return Operand(Operand::Type::literal, "$63");
|
case 14: return Operand(Operand::Type::literal, "$5c");
|
||||||
case 15: return Operand(Operand::Type::literal, "$64");
|
case 15: return Operand(Operand::Type::literal, "$5d");
|
||||||
case 16: return Operand(Operand::Type::literal, "$65");
|
case 16: return Operand(Operand::Type::literal, "$5e");
|
||||||
case 17: return Operand(Operand::Type::literal, "$69");// arithmetic register #2
|
case 17: return Operand(Operand::Type::literal, "$5f");
|
||||||
case 18: return Operand(Operand::Type::literal, "$6a");
|
case 18: return Operand(Operand::Type::literal, "$60");
|
||||||
case 19: return Operand(Operand::Type::literal, "$6b");
|
case 19: return Operand(Operand::Type::literal, "$61");
|
||||||
case 20: return Operand(Operand::Type::literal, "$6c");
|
case 20: return Operand(Operand::Type::literal, "$62");
|
||||||
case 21: return Operand(Operand::Type::literal, "$6d");
|
case 21: return Operand(Operand::Type::literal, "$63");
|
||||||
case 22: return Operand(Operand::Type::literal, "$57");// arithmetic register #3
|
case 22: return Operand(Operand::Type::literal, "$64");
|
||||||
case 23: return Operand(Operand::Type::literal, "$58");
|
case 23: return Operand(Operand::Type::literal, "$65");
|
||||||
case 24: return Operand(Operand::Type::literal, "$59");
|
case 24: return Operand(Operand::Type::literal, "$66");
|
||||||
case 25: return Operand(Operand::Type::literal, "$5a");
|
case 25: return Operand(Operand::Type::literal, "$67");
|
||||||
case 26: return Operand(Operand::Type::literal, "$5b");
|
case 26: return Operand(Operand::Type::literal, "$68");
|
||||||
case 27: return Operand(Operand::Type::literal, "$5c");// arithmetic register #4
|
case 27: return Operand(Operand::Type::literal, "$69");
|
||||||
case 28: return Operand(Operand::Type::literal, "$5d");
|
case 28: return Operand(Operand::Type::literal, "$6a");
|
||||||
case 29: return Operand(Operand::Type::literal, "$5e");
|
case 29: return Operand(Operand::Type::literal, "$6b");
|
||||||
case 30: return Operand(Operand::Type::literal, "$5f");
|
case 30: return Operand(Operand::Type::literal, "$6c");
|
||||||
case 31: return Operand(Operand::Type::literal, "$60");
|
case 31: return Operand(Operand::Type::literal, "$6d");
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num));
|
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num));
|
||||||
}
|
}
|
||||||
|
@ -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<R"(^(.*)(\+|-)[0-9]+$)">;
|
||||||
|
|
||||||
|
if (const auto results = matcher(s); results) { return results.get<1>(); }
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string fixup_8bit_literal(const std::string &s)
|
std::string fixup_8bit_literal(const std::string &s)
|
||||||
{
|
{
|
||||||
if (s[0] == '$') { return "#" + std::to_string(static_cast<uint8_t>(parse_8bit_literal(s))); }
|
if (s[0] == '$') { return "#" + std::to_string(static_cast<uint8_t>(parse_8bit_literal(s))); }
|
||||||
@ -92,6 +103,8 @@ struct AVR : ASMLine
|
|||||||
eor,
|
eor,
|
||||||
|
|
||||||
in,
|
in,
|
||||||
|
inc,
|
||||||
|
icall,
|
||||||
|
|
||||||
ld,
|
ld,
|
||||||
ldd,
|
ldd,
|
||||||
@ -140,6 +153,7 @@ struct AVR : ASMLine
|
|||||||
if (o == "rol") { return OpCode::rol; }
|
if (o == "rol") { return OpCode::rol; }
|
||||||
if (o == "ror") { return OpCode::ror; }
|
if (o == "ror") { return OpCode::ror; }
|
||||||
if (o == "rcall") { return OpCode::rcall; }
|
if (o == "rcall") { return OpCode::rcall; }
|
||||||
|
if (o == "icall") { return OpCode::icall; }
|
||||||
if (o == "call") { return OpCode::call; }
|
if (o == "call") { return OpCode::call; }
|
||||||
if (o == "ld") { return OpCode::ld; }
|
if (o == "ld") { return OpCode::ld; }
|
||||||
if (o == "sub") { return OpCode::sub; }
|
if (o == "sub") { return OpCode::sub; }
|
||||||
@ -176,6 +190,7 @@ struct AVR : ASMLine
|
|||||||
if (o == "breq") { return OpCode::breq; }
|
if (o == "breq") { return OpCode::breq; }
|
||||||
if (o == "in") { return OpCode::in; }
|
if (o == "in") { return OpCode::in; }
|
||||||
if (o == "out") { return OpCode::out; }
|
if (o == "out") { return OpCode::out; }
|
||||||
|
if (o == "inc") { return OpCode::inc; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::runtime_error(fmt::format("Unknown opcode: {}", o));
|
throw std::runtime_error(fmt::format("Unknown opcode: {}", o));
|
||||||
@ -251,7 +266,7 @@ void fixup_16_bit_N_Z_flags(std::vector<mos6502> &instructions)
|
|||||||
instructions.emplace_back(mos6502::OpCode::bmi, Operand(Operand::Type::literal, set_flag_label));
|
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
|
// 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));
|
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);
|
instructions.emplace_back(mos6502::OpCode::txa);
|
||||||
// if low order is not negative, we know it's 0 or not 0
|
// 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));
|
instructions.emplace_back(mos6502::OpCode::bpl, Operand(Operand::Type::literal, set_flag_label));
|
||||||
@ -351,6 +366,17 @@ void translate_instruction(const Personality &personality,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Unhandled call");
|
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:
|
case AVR::OpCode::rcall:
|
||||||
if (o1.value != ".") {
|
if (o1.value != ".") {
|
||||||
instructions.emplace_back(mos6502::OpCode::jsr, o1);
|
instructions.emplace_back(mos6502::OpCode::jsr, o1);
|
||||||
@ -426,6 +452,10 @@ void translate_instruction(const Personality &personality,
|
|||||||
fixup_16_bit_N_Z_flags(instructions);
|
fixup_16_bit_N_Z_flags(instructions);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case AVR::OpCode::inc:
|
||||||
|
instructions.emplace_back(mos6502::OpCode::inc, personality.get_register(o1_reg_num));
|
||||||
|
return;
|
||||||
|
|
||||||
case AVR::OpCode::subi: {
|
case AVR::OpCode::subi: {
|
||||||
// to do: deal with Carry bit (and other flags) nonsense from AVR
|
// to do: deal with Carry bit (and other flags) nonsense from AVR
|
||||||
// if |x| < |y| -> x-y +carry
|
// 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:
|
case ASMLine::Type::Directive:
|
||||||
if (from_instruction.text.starts_with(".string")) {
|
if (from_instruction.text.starts_with(".string")) {
|
||||||
instructions.emplace_back(ASMLine::Type::Directive, ".asc " + from_instruction.text.substr(7));
|
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<R"(\s*.word\s*gs\((.*)\))">;
|
||||||
|
|
||||||
|
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")) {
|
} 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")) {
|
} else if (from_instruction.text.starts_with(".zero")) {
|
||||||
const auto count = std::stoull(&*std::next(from_instruction.text.begin(), 6), nullptr, 10);
|
const auto count = std::stoull(&*std::next(from_instruction.text.begin(), 6), nullptr, 10);
|
||||||
|
|
||||||
@ -866,16 +907,24 @@ std::vector<mos6502> run(const Personality &personality, std::istream &input)
|
|||||||
std::set<std::string> used_labels{ "main", "__udivmodhi4", "__mulhi3" };
|
std::set<std::string> used_labels{ "main", "__udivmodhi4", "__mulhi3" };
|
||||||
|
|
||||||
for (const auto &i : instructions) {
|
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 (i.type == ASMLine::Type::Instruction) {
|
||||||
if (labels.count(value) != 0) { used_labels.insert(value); }
|
|
||||||
};
|
|
||||||
|
|
||||||
check_label(i.operand1.value);
|
check_label(i.operand1.value);
|
||||||
check_label(i.operand2.value);
|
check_label(i.operand2.value);
|
||||||
check_label(std::string{ strip_negate(strip_lo_hi(i.operand1.value)) });
|
check_label(std::string{ strip_offset(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.operand2.value))) });
|
||||||
|
} else if (i.type == ASMLine::Type::Directive) {
|
||||||
|
const auto matcher = ctre::match<R"(\s*.word\s*gs\((.*)\))">;
|
||||||
|
|
||||||
|
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<mos6502> run(const Personality &personality, std::istream &input)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (optimize(new_instructions, personality)) {
|
// while (optimize(new_instructions, personality)) {
|
||||||
// do it however many times it takes
|
// do it however many times it takes
|
||||||
}
|
// }
|
||||||
|
|
||||||
int branch_patch_count = 0;
|
int branch_patch_count = 0;
|
||||||
while (fix_long_branches(new_instructions, branch_patch_count)) {
|
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)
|
int main(const int argc, const char **argv)
|
||||||
{
|
{
|
||||||
|
spdlog::set_level(spdlog::level::trace);
|
||||||
const std::map<std::string, Target> targets{ { "C64", Target::C64 } };
|
const std::map<std::string, Target> targets{ { "C64", Target::C64 } };
|
||||||
CLI::App app{ "C++ Compiler for 6502 processors" };
|
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(
|
const std::string gcc_command = fmt::format(
|
||||||
"avr-gcc -fverbose-asm -c -o {outfile} -S {warning_flags} -std=c++20 -mtiny-stack "
|
"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("outfile", avr_output_file.generic_string()),
|
||||||
fmt::arg("warning_flags", warning_flags),
|
fmt::arg("warning_flags", warning_flags),
|
||||||
fmt::arg("avr", avr),
|
fmt::arg("avr", avr),
|
||||||
|
Loading…
Reference in New Issue
Block a user