mirror of
https://github.com/lefticus/6502-cpp.git
synced 2025-01-12 03:29:44 +00:00
Fix several CPU bugs and add several more instructions
This commit is contained in:
parent
b0980ac10a
commit
14b3f4192e
156
src/main.cpp
156
src/main.cpp
@ -44,23 +44,27 @@ std::string fixup_8bit_literal(const std::string &s)
|
|||||||
if (s[0] == '$')
|
if (s[0] == '$')
|
||||||
{
|
{
|
||||||
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 {
|
}
|
||||||
|
|
||||||
|
if (s.starts_with("0x")) {
|
||||||
|
return "#$" + s.substr(2);
|
||||||
|
}
|
||||||
|
|
||||||
if (s.starts_with("lo8(") && s.ends_with(")")) {
|
if (s.starts_with("lo8(") && s.ends_with(")")) {
|
||||||
return "#<" + strip_lo_hi(s);
|
return "#<" + strip_lo_hi(s);
|
||||||
}
|
}
|
||||||
if (s.starts_with("hi8(") && s.ends_with(")")) {
|
if (s.starts_with("hi8(") && s.ends_with(")")) {
|
||||||
return "#>" + strip_lo_hi(s);
|
return "#>" + strip_lo_hi(s);
|
||||||
}
|
}
|
||||||
// todo make this a generic number check
|
|
||||||
if (s == "0") {
|
const auto is_num = std::all_of(begin(s), end(s), [](const auto c){ return (c >= '0' && c <= '9') || c == '-';});
|
||||||
return "#0";
|
|
||||||
}
|
if (is_num) {
|
||||||
if (s == "1") {
|
return "#<" + s;
|
||||||
return "#1";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Operand
|
struct Operand
|
||||||
@ -133,7 +137,9 @@ struct mos6502 : ASMLine
|
|||||||
clc,
|
clc,
|
||||||
sec,
|
sec,
|
||||||
bit,
|
bit,
|
||||||
jsr
|
jsr,
|
||||||
|
bcc,
|
||||||
|
bcs
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool get_is_branch(const OpCode o) {
|
static bool get_is_branch(const OpCode o) {
|
||||||
@ -142,6 +148,8 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::bne:
|
case OpCode::bne:
|
||||||
case OpCode::bmi:
|
case OpCode::bmi:
|
||||||
case OpCode::bpl:
|
case OpCode::bpl:
|
||||||
|
case OpCode::bcc:
|
||||||
|
case OpCode::bcs:
|
||||||
return true;
|
return true;
|
||||||
case OpCode::lda:
|
case OpCode::lda:
|
||||||
case OpCode::ldy:
|
case OpCode::ldy:
|
||||||
@ -304,7 +312,11 @@ struct mos6502 : ASMLine
|
|||||||
return "jsr";
|
return "jsr";
|
||||||
case OpCode::bpl:
|
case OpCode::bpl:
|
||||||
return "bpl";
|
return "bpl";
|
||||||
case OpCode::unknown:
|
case OpCode::bcc:
|
||||||
|
return "bcc";
|
||||||
|
case OpCode::bcs:
|
||||||
|
return "bcs";
|
||||||
|
case OpCode::unknown:
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -540,7 +552,16 @@ struct AVR : ASMLine
|
|||||||
brne,
|
brne,
|
||||||
rjmp,
|
rjmp,
|
||||||
dec,
|
dec,
|
||||||
sbiw
|
sbiw,
|
||||||
|
push,
|
||||||
|
pop,
|
||||||
|
com,
|
||||||
|
swap,
|
||||||
|
clr,
|
||||||
|
cpse,
|
||||||
|
cpi,
|
||||||
|
brlo
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static OpCode parse_opcode(Type t, const std::string &o)
|
static OpCode parse_opcode(Type t, const std::string &o)
|
||||||
@ -574,6 +595,15 @@ struct AVR : ASMLine
|
|||||||
if (o == "brne") return OpCode::brne;
|
if (o == "brne") return OpCode::brne;
|
||||||
if (o == "dec") return OpCode::dec;
|
if (o == "dec") return OpCode::dec;
|
||||||
if (o == "sbiw") return OpCode::sbiw;
|
if (o == "sbiw") return OpCode::sbiw;
|
||||||
|
if (o == "push") return OpCode::push;
|
||||||
|
if (o == "pop") return OpCode::pop;
|
||||||
|
if (o == "com") return OpCode::com;
|
||||||
|
if (o == "swap") return OpCode::swap;
|
||||||
|
if (o == "clr") return OpCode::clr;
|
||||||
|
if (o == "cpse") return OpCode::cpse;
|
||||||
|
if (o == "cpi") return OpCode::cpi;
|
||||||
|
if (o == "brlo") return OpCode::brlo;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Unknown opcode: " + o);
|
throw std::runtime_error("Unknown opcode: " + o);
|
||||||
@ -732,6 +762,8 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
|
|||||||
const auto translate_register_number = [](const Operand ®) {
|
const auto translate_register_number = [](const Operand ®) {
|
||||||
if (reg.value == "__zero_reg__") {
|
if (reg.value == "__zero_reg__") {
|
||||||
return 1;
|
return 1;
|
||||||
|
} else if (reg.value == "__temp_reg__") {
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return reg.reg_num;
|
return reg.reg_num;
|
||||||
}
|
}
|
||||||
@ -849,6 +881,14 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
|
|||||||
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::cpse: {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::bit, AVR::get_register(o2_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::sbrc: {
|
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()))))));
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(o2.type, fixup_8bit_literal("$" + std::to_string(1 << (atoi(o2.value.c_str()))))));
|
||||||
instructions.emplace_back(mos6502::OpCode::bit, AVR::get_register(o1_reg_num));
|
instructions.emplace_back(mos6502::OpCode::bit, AVR::get_register(o1_reg_num));
|
||||||
@ -883,6 +923,60 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
|
|||||||
subtract_16_bit(instructions, o1_reg_num, atoi(o2.value.c_str()));
|
subtract_16_bit(instructions, o1_reg_num, atoi(o2.value.c_str()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AVR::OpCode::push: {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pha);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AVR::OpCode::pop: {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pla);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AVR::OpCode::com: {
|
||||||
|
// We're doing this in the same way the AVR does it, to make sure the C flag is set properly
|
||||||
|
instructions.emplace_back(mos6502::OpCode::clc);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$FF"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sbc, AVR::get_register(o1_reg_num));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AVR::OpCode::clr: {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AVR::OpCode::cpi: {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sec);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sbc, Operand(o2.type, fixup_8bit_literal(o2.value)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AVR::OpCode::brlo: {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::bcc, o1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AVR::OpCode::swap: {
|
||||||
|
// from http://www.6502.org/source/general/SWN.html
|
||||||
|
// ASL A
|
||||||
|
// ADC #$80
|
||||||
|
// ROL A
|
||||||
|
// ASL A
|
||||||
|
// ADC #$80
|
||||||
|
// ROL A
|
||||||
|
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, AVR::get_register(o1_reg_num));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::asl);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#$80"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::rol);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::asl);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#$80"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::rol);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, AVR::get_register(o1_reg_num));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Could not translate unhandled instruction");
|
throw std::runtime_error("Could not translate unhandled instruction");
|
||||||
@ -1287,7 +1381,8 @@ bool optimize(std::vector<mos6502> &instructions)
|
|||||||
{
|
{
|
||||||
next_instruction(op);
|
next_instruction(op);
|
||||||
if (instructions[op].opcode == mos6502::OpCode::tay) {
|
if (instructions[op].opcode == mos6502::OpCode::tay) {
|
||||||
instructions.erase(std::next(std::begin(instructions), op), std::next(std::begin(instructions), op+1));
|
instructions[op] = mos6502(ASMLine::Type::Directive,
|
||||||
|
"; removed redundant tay: " + instructions[op].to_string());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1302,12 +1397,29 @@ bool optimize(std::vector<mos6502> &instructions)
|
|||||||
if (instructions[next].opcode == mos6502::OpCode::lda
|
if (instructions[next].opcode == mos6502::OpCode::lda
|
||||||
&& instructions[next].op == instructions[op].op)
|
&& instructions[next].op == instructions[op].op)
|
||||||
{
|
{
|
||||||
instructions.erase(std::next(std::begin(instructions), next), std::next(std::begin(instructions), next+1));
|
instructions[next] = mos6502(ASMLine::Type::Directive,
|
||||||
|
"; removed redundant lda: " + instructions[next].to_string());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t op = 0; op < instructions.size() - 1; ++op) {
|
||||||
|
if (instructions[op].opcode == mos6502::OpCode::ldy && instructions[op].op.type == Operand::Type::literal) {
|
||||||
|
auto op2 = op+1;
|
||||||
|
|
||||||
|
while (op2 < instructions.size() && (instructions[op2].type != ASMLine::Type::Label)) {
|
||||||
|
// while inside this label
|
||||||
|
if (instructions[op2].opcode == mos6502::OpCode::ldy && instructions[op2].op.value ==
|
||||||
|
instructions[op].op.value) {
|
||||||
|
instructions[op2] = mos6502(ASMLine::Type::Directive, "; removed redundant ldy: " + instructions[op2].to_string());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++op2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t op = 0; op < instructions.size() - 1; ++op)
|
for (size_t op = 0; op < instructions.size() - 1; ++op)
|
||||||
{
|
{
|
||||||
if (instructions[op].opcode == mos6502::OpCode::lda
|
if (instructions[op].opcode == mos6502::OpCode::lda
|
||||||
@ -1323,14 +1435,14 @@ bool optimize(std::vector<mos6502> &instructions)
|
|||||||
if (instructions[op2].opcode == mos6502::OpCode::lda
|
if (instructions[op2].opcode == mos6502::OpCode::lda
|
||||||
&& operand == instructions[op2].op)
|
&& operand == instructions[op2].op)
|
||||||
{
|
{
|
||||||
instructions.erase(std::next(std::begin(instructions), op2), std::next(std::begin(instructions), op2+1));
|
instructions[op2] = mos6502(ASMLine::Type::Directive,
|
||||||
|
"; removed redundant lda: " + instructions[op2].to_string());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,6 +1471,14 @@ bool fix_long_branches(std::vector<mos6502> &instructions, int &branch_patch_cou
|
|||||||
instructions.insert(std::next(std::begin(instructions), op + 2), mos6502(ASMLine::Type::Label, new_pos));
|
instructions.insert(std::next(std::begin(instructions), op + 2), mos6502(ASMLine::Type::Label, new_pos));
|
||||||
instructions[op].comment = instructions[op+1].comment = instructions[op+2].comment = comment;
|
instructions[op].comment = instructions[op+1].comment = instructions[op+2].comment = comment;
|
||||||
return true;
|
return true;
|
||||||
|
} else if (instructions[op].opcode == mos6502::OpCode::bcc) {
|
||||||
|
const auto comment = instructions[op].comment;
|
||||||
|
instructions[op] = mos6502(mos6502::OpCode::bcs, Operand(Operand::Type::literal, new_pos));
|
||||||
|
instructions.insert(std::next(std::begin(instructions), op + 1),
|
||||||
|
mos6502(mos6502::OpCode::jmp, Operand(Operand::Type::literal, going_to)));
|
||||||
|
instructions.insert(std::next(std::begin(instructions), op + 2), mos6502(ASMLine::Type::Label, new_pos));
|
||||||
|
instructions[op].comment = instructions[op + 1].comment = instructions[op + 2].comment = comment;
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Don't know how to reorg this branch");
|
throw std::runtime_error("Don't know how to reorg this branch");
|
||||||
}
|
}
|
||||||
@ -1514,7 +1634,11 @@ void run(std::istream &input) {
|
|||||||
if (i.type == ASMLine::Type::Label)
|
if (i.type == ASMLine::Type::Label)
|
||||||
{
|
{
|
||||||
std::clog << "Looking up Label: '" << i.text << "'\n";
|
std::clog << "Looking up Label: '" << i.text << "'\n";
|
||||||
i.text = new_labels.at(i.text);
|
if (i.text == "0") {
|
||||||
|
i.text = "-memcpy_0";
|
||||||
|
}else {
|
||||||
|
i.text = new_labels.at(i.text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i.operand2.value.starts_with("lo8(") || i.operand2.value.starts_with("hi8("))
|
if (i.operand2.value.starts_with("lo8(") || i.operand2.value.starts_with("hi8("))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user