From 8b159faa599becb2aad49c25e339dba7292340d6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 27 May 2021 08:31:02 -0600 Subject: [PATCH] Better label handling --- examples/graphics.cpp | 98 ++++++++++++++++++++++++++++++++++++------- include/lib1funcs.hpp | 21 +++++++++- include/optimizer.hpp | 8 ++-- src/6502-c++.cpp | 98 ++++++++++++++++++++++++++----------------- 4 files changed, 166 insertions(+), 59 deletions(-) diff --git a/examples/graphics.cpp b/examples/graphics.cpp index 5b53996..de514cb 100644 --- a/examples/graphics.cpp +++ b/examples/graphics.cpp @@ -44,7 +44,8 @@ static void puts(uint8_t x, uint8_t y, std::string_view str) { const auto start = 0x400 + (y * 40 + x); - std::memcpy(const_cast(&memory_loc(start)), str.data(), str.size()); + std::copy(str.begin(), str.end(), &memory_loc(start)); +// std::memcpy(const_cast(&memory_loc(start)), str.data(), str.size()); } @@ -283,6 +284,13 @@ struct Screen } } + void hide(auto &s) { + if (s.is_shown) { + put_graphic(s.x, s.y, s.saved_background); + s.is_shown = false; + } + } + void show(std::uint8_t x, std::uint8_t y, auto &s) { if (s.is_shown) { put_graphic(s.x, s.y, s.saved_background); } @@ -309,10 +317,17 @@ struct GameState std::uint8_t x = 20; std::uint8_t y = 12; + bool redraw = true; + Clock game_clock{}; Map<10, 5> const *current_map = nullptr; + constexpr void set_current_map(const Map<10, 5> &new_map) { + current_map = &new_map; + redraw = true; + } + constexpr void execute_actions(const auto &character) noexcept { if (current_map) { @@ -374,14 +389,14 @@ struct Map_Action } const std::uint8_t rect1_x1 = x; - const std::uint8_t rect1_x2 = x + width - 1; + const std::uint8_t rect1_x2 = x + width; const std::uint8_t rect1_y1 = y; - const std::uint8_t rect1_y2 = y + height - 1; + const std::uint8_t rect1_y2 = y + height; const std::uint8_t rect2_x1 = obj_x; - const std::uint8_t rect2_x2 = obj_x + obj_width - 1; + const std::uint8_t rect2_x2 = obj_x + obj_width; const std::uint8_t rect2_y1 = obj_y; - const std::uint8_t rect2_y2 = obj_y + obj_height - 1; + const std::uint8_t rect2_y2 = obj_y + obj_height; if (rect1_x1 < rect2_x2 && rect1_x2 > rect2_x1 && rect1_y1 < rect2_y2 && rect1_y2 > rect2_y1) { @@ -393,6 +408,7 @@ struct Map_Action template struct Map { + std::string_view name; Graphic layout; std::span actions; @@ -402,6 +418,31 @@ int main() { // static constexpr auto charset = load_charset(uppercase); + static constexpr auto inn = Graphic<6,5> { + 32,233,160,160,223,32, + 233,160,160,160,160,223, + 160,137,142,142,160,160, + 160,160,160,160,79,160, + 160,160,160,160,76,160, + }; + + static constexpr auto gym = Graphic<6,5> { + 32,233,160,160,223,32, + 233,160,160,160,160,223, + 160,135,153,141,160,160, + 160,160,160,160,79,160, + 160,160,160,160,76,160, + }; + + static constexpr auto trading_post = Graphic<6,5> { + 32,233,160,160,223,32, + 233,160,160,160,160,223, + 148,146,129,132,133,160, + 160,160,160,160,79,160, + 160,160,160,160,76,160, + }; + + static constexpr auto town = Graphic<4, 4>{ 85, 67, 67, 73, 93, 233, 223, 93, @@ -420,11 +461,25 @@ int main() 78, 79, 78, 77 }; + static constexpr auto city_map = Map<10, 5>{ + "wood town", + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 0, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }, + std::span{} + }; + + static constexpr auto overview_actions = std::array { - Map_Action { 12,0,4,4, [](GameState &g) { g.x = 30; g.y=5; } } + Map_Action { 16,0,4,4, [](GameState &g) { g.set_current_map(city_map); } } }; static constexpr auto overview_map = Map<10, 5>{ + "the world", { 3, 1, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 3, 0, @@ -435,12 +490,9 @@ int main() std::span(begin(overview_actions), end(overview_actions)) }; - cls(); - poke(53280, 0); - poke(53281, 0); - static constexpr std::array tile_types{ + static constexpr std::array tile_types{ [](std::uint8_t x, std::uint8_t y) { /* do nothing for 0th */ }, @@ -449,6 +501,9 @@ int main() /* do nothing for 2 */ }, [](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, town); }, + [](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, inn); }, + [](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, gym); }, + [](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, trading_post); }, }; @@ -483,10 +538,6 @@ int main() GameState game; game.current_map = &overview_map; - // draw_map(map1); - draw_map(game.current_map->layout); - draw_box(0, 20, 40, 5); - constexpr auto show_stats = [](const auto &cur_game) { puts(1, 21, "stamina:"); put_hex(12, 21, cur_game.stamina); @@ -500,8 +551,6 @@ int main() Screen screen; - show_stats(game); - auto eventHandler = overloaded{ [&](const GameState::JoyStick2StateChanged &e) { if (e.state.up()) { --game.y; } if (e.state.down()) { ++game.y; } @@ -519,6 +568,23 @@ int main() while (true) { std::visit(eventHandler, game.next_event()); + if (game.redraw) { + screen.hide(character); + cls(); + + poke(53280, 0); + poke(53281, 0); + + game.redraw = false; + draw_map(game.current_map->layout); + draw_box(0, 20, 40, 5); + + puts(10, 20, game.current_map->name); + show_stats(game); + screen.show(game.x, game.y, character); + } + + increment_border_color(); } diff --git a/include/lib1funcs.hpp b/include/lib1funcs.hpp index a4c2e46..ac1f181 100644 --- a/include/lib1funcs.hpp +++ b/include/lib1funcs.hpp @@ -2,7 +2,7 @@ static constexpr std::string_view __mulhi3 = R"( ;;; based on protocol from gcc's calling conventions for AVR - +;;; 16x16 = 16 multiply ;;; R25:R24 = R23:R22 * R25:R24 ;;; Clobbers: __tmp_reg__, R21..R23 @@ -33,3 +33,22 @@ __mulhi3: )"; +static constexpr std::string_view __mulqi3 = + R"( +;;; based on protocol from gcc's calling conventions for AVR +;;; 8x8 = 8 multiply +;;; R24 = R22 * R24 +;;; Clobbers: __tmp_reg__, R22, R24 + +__mulqi3: + ldi __temp_reg__,0 +__mulqi_1: + sbrc r24,0 + add __temp_reg__,r22 + lsr r24 + lsl r22 + cpse r24,__zero_reg__ + rjmp __mulqi_1 + mov r24, __temp_reg__ + ret +)"; \ No newline at end of file diff --git a/include/optimizer.hpp b/include/optimizer.hpp index d4c0faa..53aace8 100644 --- a/include/optimizer.hpp +++ b/include/optimizer.hpp @@ -285,13 +285,15 @@ bool optimize(std::vector &instructions, [[maybe_unused]] const Persona } } - bool block_optimized = false; + bool optimizer_run = false; for (auto &block : get_optimizable_blocks(instructions)) { - block_optimized = block_optimized || optimize_redundant_lda_after_sta(block) + const bool block_optimized = optimize_redundant_lda_after_sta(block) || optimize_dead_sta(block, personality) || optimize_dead_tax(block) || optimize_redundant_ldy(block) || optimize_redundant_lda(block, personality); + + optimizer_run = optimizer_run || block_optimized; } - return block_optimized; + return optimizer_run; } #endif// INC_6502_CPP_OPTIMIZER_HPP diff --git a/src/6502-c++.cpp b/src/6502-c++.cpp index f8c187b..51f2793 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -72,8 +72,8 @@ std::string fixup_8bit_literal(const std::string &s) if (s.starts_with("0x")) { return "#$" + s.substr(2); } - if (s.starts_with("lo8(")) { return fmt::format("#<{}", strip_gs(strip_lo_hi(s))); } - if (s.starts_with("hi8(")) { return fmt::format("#>{}", strip_gs(strip_lo_hi(s))); } + if (s.starts_with("lo8(")) { return fmt::format("#<({})", strip_gs(strip_lo_hi(s))); } + if (s.starts_with("hi8(")) { return fmt::format("#>({})", strip_gs(strip_lo_hi(s))); } const auto is_num = std::all_of(begin(s), end(s), [](const auto c) { return (c >= '0' && c <= '9') || c == '-'; }); @@ -292,12 +292,14 @@ void fixup_16_bit_N_Z_flags(std::vector &instructions) instructions.emplace_back(ASMLine::Type::Directive, "; END remove if next is lda, bcc, bcs, ldy"); } -void add_16_bit(const Personality &personality, std::vector &instructions, int reg, const std::string_view value) +void add_16_bit(const Personality &personality, + std::vector &instructions, + int reg, + const std::string_view value) { 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, fmt::format("#({})", value))); + instructions.emplace_back(mos6502::OpCode::adc, Operand(Operand::Type::literal, fmt::format("#({})", value))); 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)); @@ -330,13 +332,11 @@ void subtract_16_bit(const Personality &personality, { 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, fmt::format("#({})", value))); + instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, fmt::format("#({})", value))); 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, "#0")); + instructions.emplace_back(mos6502::OpCode::sbc, Operand(Operand::Type::literal, "#0")); instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1)); fixup_16_bit_N_Z_flags(instructions); @@ -809,14 +809,14 @@ void to_mos6502(const Personality &personality, const AVR &from_instruction, std 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; + const auto matcher = ctre::match; 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); + instructions.emplace_back(ASMLine::Type::Directive, ".word " + std::string{strip_gs(matched_gs)}); } else { instructions.emplace_back(ASMLine::Type::Directive, ".word " + from_instruction.text.substr(6)); - // spdlog::warn("Unknown .word directive '{}'", from_instruction.text); + // spdlog::warn("Unknown .word directive '{}'", from_instruction.text); } } else if (from_instruction.text.starts_with(".byte")) { @@ -973,8 +973,12 @@ std::vector run(const Personality &personality, std::istream &input, co const bool needs_mulhi3 = std::any_of(begin(instructions), end(instructions), [](const AVR &instruction) { return instruction.line_text.find("__mulhi3") != std::string::npos; }); + const bool needs_mulqi3 = std::any_of(begin(instructions), end(instructions), [](const AVR &instruction) { + return instruction.line_text.find("__mulqi3") != std::string::npos; + }); if (needs_mulhi3) { parse_string(__mulhi3); } + if (needs_mulqi3) { parse_string(__mulqi3); } std::set labels; @@ -995,13 +999,15 @@ std::vector run(const Personality &personality, std::istream &input, co check_label(i.operand2.value); check_label(std::string{ strip_gs(strip_offset(strip_negate(strip_lo_hi(i.operand1.value)))) }); check_label(std::string{ strip_gs(strip_offset(strip_negate(strip_lo_hi(i.operand2.value)))) }); + + } else if (i.type == ASMLine::Type::Directive) { - const auto matcher = ctre::match; + const auto matcher = ctre::match; 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); + spdlog::trace("matched .word: '{}' from '{}'", matched_gs, i.text); + check_label(std::string{strip_gs(matched_gs)}); } } } @@ -1009,10 +1015,6 @@ std::vector run(const Personality &personality, std::istream &input, co const auto new_labels = [&used_labels]() { std::map result; for (const auto &l : used_labels) { - // auto newl = l; - // std::transform(newl.begin(), newl.end(), newl.begin(), [](const auto c) { return std::tolower(c); }); - // newl.erase(std::remove_if(newl.begin(), newl.end(), [](const auto c) { return !std::isalnum(c); }), - // std::end(newl)); const auto new_label = [](auto label) -> std::string { if (label[0] == '.') { label.erase(0, 1); } @@ -1044,10 +1046,28 @@ std::vector run(const Personality &personality, std::istream &input, co } } + if (i.type == ASMLine::Type::Directive) { + const auto matcher = ctre::match; + + if (const auto results = matcher(i.text); results) { + const auto matched_gs = results.get<1>().to_string(); + const auto possible_label = std::string{ strip_gs(matched_gs) }; + const auto matched_label = new_labels.find(possible_label); + if (matched_label != new_labels.end()) { + i.text = ".word " + matched_label->second; + } + } + } + if (i.operand2.value.starts_with("lo8(") || i.operand2.value.starts_with("hi8(")) { - const auto potential_label = strip_lo_hi(i.operand2.value); - const auto itr1 = new_labels.find(std::string{ potential_label }); - if (itr1 != new_labels.end()) { i.operand2.value.replace(4, potential_label.size(), itr1->second); } + const auto lo_hi_operand = strip_lo_hi(i.operand2.value); + const auto label_matcher = ctre::match; + + if (const auto results = label_matcher(lo_hi_operand); results) { + std::string_view potential_label = results.get<1>(); + const auto itr1 = new_labels.find(std::string{ potential_label }); + if (itr1 != new_labels.end()) { i.operand2.value.replace(4, potential_label.size(), itr1->second); } + } } const auto itr1 = new_labels.find(i.operand1.value); @@ -1158,23 +1178,23 @@ int main(const int argc, const char **argv) const auto program_output_file = make_output_file_name(filename, "prg"); std::string disabled_optimizations; -/* - disabled_optimizations += " -fno-gcse-after-reload"; - disabled_optimizations += " -fno-ipa-cp-clone"; - disabled_optimizations += " -fno-loop-interchange"; - disabled_optimizations += " -fno-loop-unroll-and-jam"; - disabled_optimizations += " -fno-peel-loops"; - disabled_optimizations += " -fno-predictive-commoning"; - disabled_optimizations += " -fno-split-loops"; - disabled_optimizations += " -fno-split-paths"; - disabled_optimizations += " -fno-tree-loop-distribution"; - disabled_optimizations += " -fno-tree-loop-vectorize"; - disabled_optimizations += " -fno-tree-partial-pre"; - disabled_optimizations += " -fno-tree-slp-vectorize"; - disabled_optimizations += " -fno-unswitch-loops"; - disabled_optimizations += " -fvect-cost-model=cheap"; - disabled_optimizations += " -fno-version-loops-for-strides"; - */ + /* + disabled_optimizations += " -fno-gcse-after-reload"; + disabled_optimizations += " -fno-ipa-cp-clone"; + disabled_optimizations += " -fno-loop-interchange"; + disabled_optimizations += " -fno-loop-unroll-and-jam"; + disabled_optimizations += " -fno-peel-loops"; + disabled_optimizations += " -fno-predictive-commoning"; + disabled_optimizations += " -fno-split-loops"; + disabled_optimizations += " -fno-split-paths"; + disabled_optimizations += " -fno-tree-loop-distribution"; + disabled_optimizations += " -fno-tree-loop-vectorize"; + disabled_optimizations += " -fno-tree-partial-pre"; + disabled_optimizations += " -fno-tree-slp-vectorize"; + disabled_optimizations += " -fno-unswitch-loops"; + disabled_optimizations += " -fvect-cost-model=cheap"; + disabled_optimizations += " -fno-version-loops-for-strides"; + */ const std::string gcc_command = fmt::format( "avr-gcc -fverbose-asm -c -o {outfile} -S {warning_flags} -std=c++20 -mtiny-stack "