From a4edf7194e4d10e0e5c879223b9de1dd1790846b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 8 May 2021 22:58:55 -0600 Subject: [PATCH] Better stack handling. We now require -mtiny-stack from GCC --- compile.sh | 2 +- include/6502.hpp | 16 ++++++++++++++++ include/optimizer.hpp | 8 +++++++- include/personalities/c64.hpp | 3 --- src/6502-c++.cpp | 33 +++++++++++++++++++++++++-------- 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/compile.sh b/compile.sh index d75d0d5..c8c0fcc 100755 --- a/compile.sh +++ b/compile.sh @@ -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 diff --git a/include/6502.hpp b/include/6502.hpp index e14cfdb..cc8914e 100644 --- a/include/6502.hpp +++ b/include/6502.hpp @@ -34,6 +34,7 @@ struct mos6502 : ASMLine jsr, lda, + ldx, ldy, lsr, @@ -51,11 +52,14 @@ struct mos6502 : ASMLine sbc, sec, sta, + stx, sty, tax, tay, + tsx, txa, + txs, tya, }; @@ -82,6 +86,7 @@ struct mos6502 : ASMLine case OpCode::jmp: case OpCode::jsr: case OpCode::lda: + case OpCode::ldx: case OpCode::ldy: case OpCode::lsr: case OpCode::ORA: @@ -96,9 +101,12 @@ struct mos6502 : ASMLine case OpCode::sec: case OpCode::sta: case OpCode::sty: + case OpCode::stx: case OpCode::tax: case OpCode::tay: + case OpCode::tsx: case OpCode::txa: + case OpCode::txs: case OpCode::tya: case OpCode::unknown: @@ -130,6 +138,7 @@ struct mos6502 : ASMLine case OpCode::jmp: case OpCode::jsr: case OpCode::lda: + case OpCode::ldx: case OpCode::ldy: case OpCode::lsr: case OpCode::ORA: @@ -143,10 +152,13 @@ struct mos6502 : ASMLine case OpCode::sbc: case OpCode::sec: case OpCode::sta: + case OpCode::stx: case OpCode::sty: case OpCode::tax: case OpCode::tay: + case OpCode::tsx: case OpCode::txa: + case OpCode::txs: case OpCode::tya: case OpCode::unknown: break; @@ -176,15 +188,19 @@ struct mos6502 : ASMLine case OpCode::lda: return "lda"; case OpCode::asl: return "asl"; case OpCode::rol: return "rol"; + case OpCode::ldx: return "ldx"; case OpCode::ldy: return "ldy"; case OpCode::tay: return "tay"; case OpCode::tya: return "tya"; case OpCode::tax: return "tax"; + case OpCode::tsx: return "tsx"; case OpCode::txa: return "txa"; + case OpCode::txs: return "txs"; case OpCode::cpy: return "cpy"; case OpCode::eor: return "eor"; case OpCode::sta: return "sta"; case OpCode::sty: return "sty"; + case OpCode::stx: return "stx"; case OpCode::pha: return "pha"; case OpCode::pla: return "pla"; case OpCode::php: return "php"; diff --git a/include/optimizer.hpp b/include/optimizer.hpp index dd442de..69fc036 100644 --- a/include/optimizer.hpp +++ b/include/optimizer.hpp @@ -103,6 +103,10 @@ bool optimize(std::vector &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) { if (instructions[op].opcode == mos6502::OpCode::ldy && instructions[op].op.type == Operand::Type::literal) { auto op2 = op + 1; @@ -116,7 +120,9 @@ bool optimize(std::vector &instructions) ++op2; } } - } + } + */ + for (size_t op = 0; op < instructions.size() - 1; ++op) { if (instructions[op].opcode == mos6502::OpCode::lda diff --git a/include/personalities/c64.hpp b/include/personalities/c64.hpp index bd52036..2863579 100644 --- a/include/personalities/c64.hpp +++ b/include/personalities/c64.hpp @@ -100,9 +100,6 @@ struct C64 : Personality return Operand(Operand::Type::literal, "$5f"); case 31: 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)); } diff --git a/src/6502-c++.cpp b/src/6502-c++.cpp index e9fa100..41f163a 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -116,6 +116,8 @@ struct AVR : ASMLine mov, + out, + pop, push, @@ -185,6 +187,7 @@ struct AVR : ASMLine if (o == "brsh") { return OpCode::brsh; } if (o == "breq") { return OpCode::breq; } if (o == "in") { return OpCode::in; } + if (o == "out") { return OpCode::out; } } } throw std::runtime_error(fmt::format("Unknown opcode: {}", o)); @@ -249,7 +252,7 @@ void fixup_16_bit_N_Z_flags(std::vector &instructions) { // 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, "; 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()); @@ -269,29 +272,29 @@ void fixup_16_bit_N_Z_flags(std::vector &instructions) void add_16_bit(const Personality &personality, std::vector &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::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::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::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::tax); + fixup_16_bit_N_Z_flags(instructions); } void subtract_16_bit(const Personality &personality, std::vector &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::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::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::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::tax); + fixup_16_bit_N_Z_flags(instructions); } @@ -626,16 +629,30 @@ void translate_instruction(const Personality &personality, std::vector 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: { 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::sta, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::tsx); + instructions.emplace_back(mos6502::OpCode::stx, personality.get_register(o1_reg_num)); return; } 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)); return; }