mirror of
https://github.com/lefticus/6502-cpp.git
synced 2024-12-21 10:30:35 +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] == '$')
|
||||
{
|
||||
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(")")) {
|
||||
return "#<" + strip_lo_hi(s);
|
||||
}
|
||||
if (s.starts_with("hi8(") && s.ends_with(")")) {
|
||||
return "#>" + strip_lo_hi(s);
|
||||
}
|
||||
// todo make this a generic number check
|
||||
if (s == "0") {
|
||||
return "#0";
|
||||
}
|
||||
if (s == "1") {
|
||||
return "#1";
|
||||
|
||||
const auto is_num = std::all_of(begin(s), end(s), [](const auto c){ return (c >= '0' && c <= '9') || c == '-';});
|
||||
|
||||
if (is_num) {
|
||||
return "#<" + s;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct Operand
|
||||
@ -133,7 +137,9 @@ struct mos6502 : ASMLine
|
||||
clc,
|
||||
sec,
|
||||
bit,
|
||||
jsr
|
||||
jsr,
|
||||
bcc,
|
||||
bcs
|
||||
};
|
||||
|
||||
static bool get_is_branch(const OpCode o) {
|
||||
@ -142,6 +148,8 @@ struct mos6502 : ASMLine
|
||||
case OpCode::bne:
|
||||
case OpCode::bmi:
|
||||
case OpCode::bpl:
|
||||
case OpCode::bcc:
|
||||
case OpCode::bcs:
|
||||
return true;
|
||||
case OpCode::lda:
|
||||
case OpCode::ldy:
|
||||
@ -304,7 +312,11 @@ struct mos6502 : ASMLine
|
||||
return "jsr";
|
||||
case OpCode::bpl:
|
||||
return "bpl";
|
||||
case OpCode::unknown:
|
||||
case OpCode::bcc:
|
||||
return "bcc";
|
||||
case OpCode::bcs:
|
||||
return "bcs";
|
||||
case OpCode::unknown:
|
||||
return "";
|
||||
};
|
||||
|
||||
@ -540,7 +552,16 @@ struct AVR : ASMLine
|
||||
brne,
|
||||
rjmp,
|
||||
dec,
|
||||
sbiw
|
||||
sbiw,
|
||||
push,
|
||||
pop,
|
||||
com,
|
||||
swap,
|
||||
clr,
|
||||
cpse,
|
||||
cpi,
|
||||
brlo
|
||||
|
||||
};
|
||||
|
||||
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 == "dec") return OpCode::dec;
|
||||
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);
|
||||
@ -732,6 +762,8 @@ void translate_instruction(std::vector<mos6502> &instructions, const AVR::OpCode
|
||||
const auto translate_register_number = [](const Operand ®) {
|
||||
if (reg.value == "__zero_reg__") {
|
||||
return 1;
|
||||
} else if (reg.value == "__temp_reg__") {
|
||||
return 0;
|
||||
} else {
|
||||
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));
|
||||
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: {
|
||||
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));
|
||||
@ -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()));
|
||||
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");
|
||||
@ -1287,7 +1381,8 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
{
|
||||
next_instruction(op);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1302,12 +1397,29 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
if (instructions[next].opcode == mos6502::OpCode::lda
|
||||
&& 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (instructions[op].opcode == mos6502::OpCode::lda
|
||||
@ -1323,14 +1435,14 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
if (instructions[op2].opcode == mos6502::OpCode::lda
|
||||
&& 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 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[op].comment = instructions[op+1].comment = instructions[op+2].comment = comment;
|
||||
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 {
|
||||
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)
|
||||
{
|
||||
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("))
|
||||
|
Loading…
Reference in New Issue
Block a user