mirror of
https://github.com/lefticus/6502-cpp.git
synced 2024-12-21 10:30:35 +00:00
Better stack handling. We now require -mtiny-stack from GCC
This commit is contained in:
parent
baf9c092ea
commit
a4edf7194e
@ -1 +1 @@
|
|||||||
avr-gcc $1 -Wall -Wextra -c -o- -S -O3 -I ~/avr-libstdcpp/include/ -std=c++20 | tee $1.asm | ./avr-to-6502 | tee $1.asm && xa -O PETSCREEN -M $1.prg
|
avr-gcc $1 -Wall -Wextra -mtiny-stack -c -o- -S -O3 -I ~/avr-libstdcpp/include/ -std=c++20 | tee $1.asm | ./avr-to-6502 | tee $1.asm && xa -O PETSCREEN -M $1.prg
|
||||||
|
@ -34,6 +34,7 @@ struct mos6502 : ASMLine
|
|||||||
jsr,
|
jsr,
|
||||||
|
|
||||||
lda,
|
lda,
|
||||||
|
ldx,
|
||||||
ldy,
|
ldy,
|
||||||
lsr,
|
lsr,
|
||||||
|
|
||||||
@ -51,11 +52,14 @@ struct mos6502 : ASMLine
|
|||||||
sbc,
|
sbc,
|
||||||
sec,
|
sec,
|
||||||
sta,
|
sta,
|
||||||
|
stx,
|
||||||
sty,
|
sty,
|
||||||
|
|
||||||
tax,
|
tax,
|
||||||
tay,
|
tay,
|
||||||
|
tsx,
|
||||||
txa,
|
txa,
|
||||||
|
txs,
|
||||||
tya,
|
tya,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -82,6 +86,7 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::jmp:
|
case OpCode::jmp:
|
||||||
case OpCode::jsr:
|
case OpCode::jsr:
|
||||||
case OpCode::lda:
|
case OpCode::lda:
|
||||||
|
case OpCode::ldx:
|
||||||
case OpCode::ldy:
|
case OpCode::ldy:
|
||||||
case OpCode::lsr:
|
case OpCode::lsr:
|
||||||
case OpCode::ORA:
|
case OpCode::ORA:
|
||||||
@ -96,9 +101,12 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::sec:
|
case OpCode::sec:
|
||||||
case OpCode::sta:
|
case OpCode::sta:
|
||||||
case OpCode::sty:
|
case OpCode::sty:
|
||||||
|
case OpCode::stx:
|
||||||
case OpCode::tax:
|
case OpCode::tax:
|
||||||
case OpCode::tay:
|
case OpCode::tay:
|
||||||
|
case OpCode::tsx:
|
||||||
case OpCode::txa:
|
case OpCode::txa:
|
||||||
|
case OpCode::txs:
|
||||||
case OpCode::tya:
|
case OpCode::tya:
|
||||||
|
|
||||||
case OpCode::unknown:
|
case OpCode::unknown:
|
||||||
@ -130,6 +138,7 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::jmp:
|
case OpCode::jmp:
|
||||||
case OpCode::jsr:
|
case OpCode::jsr:
|
||||||
case OpCode::lda:
|
case OpCode::lda:
|
||||||
|
case OpCode::ldx:
|
||||||
case OpCode::ldy:
|
case OpCode::ldy:
|
||||||
case OpCode::lsr:
|
case OpCode::lsr:
|
||||||
case OpCode::ORA:
|
case OpCode::ORA:
|
||||||
@ -143,10 +152,13 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::sbc:
|
case OpCode::sbc:
|
||||||
case OpCode::sec:
|
case OpCode::sec:
|
||||||
case OpCode::sta:
|
case OpCode::sta:
|
||||||
|
case OpCode::stx:
|
||||||
case OpCode::sty:
|
case OpCode::sty:
|
||||||
case OpCode::tax:
|
case OpCode::tax:
|
||||||
case OpCode::tay:
|
case OpCode::tay:
|
||||||
|
case OpCode::tsx:
|
||||||
case OpCode::txa:
|
case OpCode::txa:
|
||||||
|
case OpCode::txs:
|
||||||
case OpCode::tya:
|
case OpCode::tya:
|
||||||
case OpCode::unknown:
|
case OpCode::unknown:
|
||||||
break;
|
break;
|
||||||
@ -176,15 +188,19 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::lda: return "lda";
|
case OpCode::lda: return "lda";
|
||||||
case OpCode::asl: return "asl";
|
case OpCode::asl: return "asl";
|
||||||
case OpCode::rol: return "rol";
|
case OpCode::rol: return "rol";
|
||||||
|
case OpCode::ldx: return "ldx";
|
||||||
case OpCode::ldy: return "ldy";
|
case OpCode::ldy: return "ldy";
|
||||||
case OpCode::tay: return "tay";
|
case OpCode::tay: return "tay";
|
||||||
case OpCode::tya: return "tya";
|
case OpCode::tya: return "tya";
|
||||||
case OpCode::tax: return "tax";
|
case OpCode::tax: return "tax";
|
||||||
|
case OpCode::tsx: return "tsx";
|
||||||
case OpCode::txa: return "txa";
|
case OpCode::txa: return "txa";
|
||||||
|
case OpCode::txs: return "txs";
|
||||||
case OpCode::cpy: return "cpy";
|
case OpCode::cpy: return "cpy";
|
||||||
case OpCode::eor: return "eor";
|
case OpCode::eor: return "eor";
|
||||||
case OpCode::sta: return "sta";
|
case OpCode::sta: return "sta";
|
||||||
case OpCode::sty: return "sty";
|
case OpCode::sty: return "sty";
|
||||||
|
case OpCode::stx: return "stx";
|
||||||
case OpCode::pha: return "pha";
|
case OpCode::pha: return "pha";
|
||||||
case OpCode::pla: return "pla";
|
case OpCode::pla: return "pla";
|
||||||
case OpCode::php: return "php";
|
case OpCode::php: return "php";
|
||||||
|
@ -103,6 +103,10 @@ bool optimize(std::vector<mos6502> &instructions)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: fix this ldy redundant move, right now it doesn't
|
||||||
|
// take into account if Y has been used
|
||||||
|
|
||||||
|
/*
|
||||||
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::ldy && instructions[op].op.type == Operand::Type::literal) {
|
if (instructions[op].opcode == mos6502::OpCode::ldy && instructions[op].op.type == Operand::Type::literal) {
|
||||||
auto op2 = op + 1;
|
auto op2 = op + 1;
|
||||||
@ -116,7 +120,9 @@ bool optimize(std::vector<mos6502> &instructions)
|
|||||||
++op2;
|
++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
|
||||||
|
@ -100,9 +100,6 @@ struct C64 : Personality
|
|||||||
return Operand(Operand::Type::literal, "$5f");
|
return Operand(Operand::Type::literal, "$5f");
|
||||||
case 31:
|
case 31:
|
||||||
return Operand(Operand::Type::literal, "$60");
|
return Operand(Operand::Type::literal, "$60");
|
||||||
case 32:
|
|
||||||
// 32 is the "Stack Pointer", because I decided so, I mean, it makes sense
|
|
||||||
return Operand(Operand::Type::literal, std::string{stack_low_address()});
|
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num));
|
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num));
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,8 @@ struct AVR : ASMLine
|
|||||||
|
|
||||||
mov,
|
mov,
|
||||||
|
|
||||||
|
out,
|
||||||
|
|
||||||
pop,
|
pop,
|
||||||
push,
|
push,
|
||||||
|
|
||||||
@ -185,6 +187,7 @@ struct AVR : ASMLine
|
|||||||
if (o == "brsh") { return OpCode::brsh; }
|
if (o == "brsh") { return OpCode::brsh; }
|
||||||
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::runtime_error(fmt::format("Unknown opcode: {}", o));
|
throw std::runtime_error(fmt::format("Unknown opcode: {}", o));
|
||||||
@ -249,7 +252,7 @@ void fixup_16_bit_N_Z_flags(std::vector<mos6502> &instructions)
|
|||||||
{
|
{
|
||||||
|
|
||||||
// need to get both Z and N set appropriately
|
// need to get both Z and N set appropriately
|
||||||
// assuming A contains higher order byte and Y contains lower order byte
|
// assuming A contains higher order byte and X contains lower order byte
|
||||||
instructions.emplace_back(ASMLine::Type::Directive, "; BEGIN remove if next is lda");
|
instructions.emplace_back(ASMLine::Type::Directive, "; BEGIN remove if next is lda");
|
||||||
instructions.emplace_back(ASMLine::Type::Directive, "; set CPU flags assuming A holds the higher order byte already");
|
instructions.emplace_back(ASMLine::Type::Directive, "; set CPU flags assuming A holds the higher order byte already");
|
||||||
std::string set_flag_label = "flags_set_after_16_bit_op_" + std::to_string(instructions.size());
|
std::string set_flag_label = "flags_set_after_16_bit_op_" + std::to_string(instructions.size());
|
||||||
@ -269,29 +272,29 @@ void fixup_16_bit_N_Z_flags(std::vector<mos6502> &instructions)
|
|||||||
|
|
||||||
void add_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg, const std::uint16_t value)
|
void add_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg, const std::uint16_t value)
|
||||||
{
|
{
|
||||||
//instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, address_low_byte));
|
|
||||||
instructions.emplace_back(mos6502::OpCode::clc);
|
instructions.emplace_back(mos6502::OpCode::clc);
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg));
|
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg));
|
||||||
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#" + std::to_string((value & 0xFFu))));
|
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#" + std::to_string((value & 0xFFu))));
|
||||||
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg));
|
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::tax);
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg + 1));
|
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg + 1));
|
||||||
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#" + std::to_string((value >> 8u) & 0xFFu)));
|
instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, "#" + std::to_string((value >> 8u) & 0xFFu)));
|
||||||
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1));
|
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1));
|
||||||
instructions.emplace_back(mos6502::OpCode::tax);
|
|
||||||
fixup_16_bit_N_Z_flags(instructions);
|
fixup_16_bit_N_Z_flags(instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void subtract_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg, const std::uint16_t value)
|
void subtract_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg, const std::uint16_t value)
|
||||||
{
|
{
|
||||||
//instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, address_low_byte));
|
|
||||||
instructions.emplace_back(mos6502::OpCode::sec);
|
instructions.emplace_back(mos6502::OpCode::sec);
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg));
|
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg));
|
||||||
instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value & 0xFFu))));
|
instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value & 0xFFu))));
|
||||||
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg));
|
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::tax);
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg + 1));
|
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(reg + 1));
|
||||||
instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value >> 8u) & 0xFFu)));
|
instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#" + std::to_string((value >> 8u) & 0xFFu)));
|
||||||
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1));
|
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1));
|
||||||
instructions.emplace_back(mos6502::OpCode::tax);
|
|
||||||
fixup_16_bit_N_Z_flags(instructions);
|
fixup_16_bit_N_Z_flags(instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,16 +629,30 @@ void translate_instruction(const Personality &personality, std::vector<mos6502>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case AVR::OpCode::out: {
|
||||||
|
if (o1.value == "__SP_L__") {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::ldx, personality.get_register(o2_reg_num));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::txs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o1.value == "__SP_H__") {
|
||||||
|
// officially nothing to do - we cannot change the high byte of the SP on 6502
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Could not translate unknown 'out' instruction");
|
||||||
|
}
|
||||||
|
|
||||||
case AVR::OpCode::in: {
|
case AVR::OpCode::in: {
|
||||||
if (o2.value == "__SP_L__") {
|
if (o2.value == "__SP_L__") {
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, std::string{ personality.stack_low_address() }));
|
instructions.emplace_back(mos6502::OpCode::tsx);
|
||||||
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
|
instructions.emplace_back(mos6502::OpCode::stx, personality.get_register(o1_reg_num));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o2.value == "__SP_H__") {
|
if (o2.value == "__SP_H__") {
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, std::string{ personality.stack_high_address() }));
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "$01"));
|
||||||
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
|
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user