diff --git a/examples/graphics.cpp b/examples/graphics.cpp index 6b9223c..0b6040a 100644 --- a/examples/graphics.cpp +++ b/examples/graphics.cpp @@ -24,6 +24,28 @@ static void decrement_border_color() { --memory_loc(0xd020); } static void increment_border_color() { ++memory_loc(0xd020); } + +struct Joystick +{ + std::uint8_t state{}; + + constexpr bool up() const noexcept { + return (state & 1) == 0; + } + constexpr bool left() const noexcept { + return (state & 4) == 0; + } + constexpr bool fire() const noexcept { + return (state & 16) == 0; + } + constexpr bool right() const noexcept { + return (state & 8) == 0; + } + constexpr bool down() const noexcept { + return (state & 2) == 0; + } +}; + static bool joystick_down() { uint8_t joystick_state = peek(0xDC00); return (joystick_state & 2) == 0; @@ -287,6 +309,11 @@ struct SimpleSprite }; +// helper type for the visitor #4 +template struct overloaded : Ts... { using Ts::operator()...; }; +// explicit deduction guide (not needed as of C++20) +template overloaded(Ts...) -> overloaded; + struct Screen { void load(std::uint8_t x, std::uint8_t y, auto &s) { @@ -413,9 +440,15 @@ int main() { return endurance * 5; } - struct JoyStickStateChanged + struct JoyStick1StateChanged { - std::uint8_t state; + Joystick state; + }; + + + struct JoyStick2StateChanged + { + Joystick state; }; struct TimeElapsed @@ -423,16 +456,16 @@ int main() { Clock::milliseconds us; }; - using Event = std::variant; + using Event = std::variant; - std::uint8_t last_joystick_state = peek(0xDC00); + std::uint8_t last_joystick_2_state = peek(0xDC00); Event next_event() noexcept { - const auto new_joystick_state = peek(0xDC00); + const auto new_joystick_2_state = peek(0xDC00); - if (new_joystick_state != last_joystick_state) { - last_joystick_state = new_joystick_state; - return JoyStickStateChanged{new_joystick_state}; + if (new_joystick_2_state != last_joystick_2_state) { + last_joystick_2_state = new_joystick_2_state; + return JoyStick2StateChanged{Joystick{new_joystick_2_state}}; } return TimeElapsed{game_clock.restart()}; @@ -460,30 +493,35 @@ int main() { show_stats(game); - std::uint8_t x = 0; + std::uint8_t x = 20; + std::uint8_t y = 12; - struct HandleEvents { + auto eventHandler = overloaded { + [&](const GameState::JoyStick2StateChanged &e) { + if (e.state.up()) { + --y; + } + if (e.state.down()) { + ++y; + } + if (e.state.left()) { + --x; + } + if (e.state.right()) { + ++x; + } + screen.show(x, y, character); - void operator()(const GameState::JoyStickStateChanged &e) { - put_hex(36, 1, e.state); - } - - void operator()(const GameState::TimeElapsed &e) { + put_hex(36, 1, e.state.state); + }, + [](const GameState::TimeElapsed &e) { put_hex(36, 0, e.us.count()); } - }; - HandleEvents eventHandler; - while (true) { std::visit(eventHandler, game.next_event()); - screen.show(x++, 10, character); - - if (x == 11) { - x = 10; - } increment_border_color(); } diff --git a/src/6502-c++.cpp b/src/6502-c++.cpp index 47547ef..3f40fd7 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -51,9 +51,7 @@ std::string_view strip_gs(std::string_view s) { const auto matcher = ctre::match; - if (const auto results = matcher(s); results) { - return results.get<1>(); - } + if (const auto results = matcher(s); results) { return results.get<1>(); } return s; } @@ -294,6 +292,21 @@ void fixup_16_bit_N_Z_flags(std::vector &instructions) instructions.emplace_back(ASMLine::Type::Directive, "; END remove if next is lda, bcc, bcs"); } +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::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, "#0")); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(reg + 1)); + + fixup_16_bit_N_Z_flags(instructions); +} + void add_16_bit(const Personality &personality, std::vector &instructions, int reg, const std::uint16_t value) { instructions.emplace_back(mos6502::OpCode::clc); @@ -310,6 +323,25 @@ void add_16_bit(const Personality &personality, std::vector &instructio fixup_16_bit_N_Z_flags(instructions); } +void subtract_16_bit(const Personality &personality, + std::vector &instructions, + int reg, + const std::string_view value) +{ + 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::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::sta, personality.get_register(reg + 1)); + + fixup_16_bit_N_Z_flags(instructions); +} + void subtract_16_bit(const Personality &personality, std::vector &instructions, int reg, @@ -331,11 +363,10 @@ void subtract_16_bit(const Personality &personality, void increment_16_bit(const Personality &personality, std::vector &instructions, int reg) { - std::string skip_high_byte_label = - "skip_inc_high_byte_" + std::to_string(instructions.size()); + std::string skip_high_byte_label = "skip_inc_high_byte_" + std::to_string(instructions.size()); instructions.emplace_back(mos6502::OpCode::inc, personality.get_register(reg)); instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, skip_high_byte_label)); - instructions.emplace_back(mos6502::OpCode::inc, personality.get_register(reg+1)); + instructions.emplace_back(mos6502::OpCode::inc, personality.get_register(reg + 1)); instructions.emplace_back(ASMLine::Type::Label, skip_high_byte_label); } @@ -365,8 +396,6 @@ void translate_instruction(const Personality &personality, // sufficient instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); return; - - } case AVR::OpCode::dec: instructions.emplace_back(mos6502::OpCode::dec, personality.get_register(o1_reg_num)); return; case AVR::OpCode::ldi: @@ -591,12 +620,12 @@ void translate_instruction(const Personality &personality, } case AVR::OpCode::sbiw: { - subtract_16_bit(personality, instructions, o1_reg_num, static_cast(to_int(o2.value))); + subtract_16_bit(personality, instructions, o1_reg_num, o2.value); return; } case AVR::OpCode::adiw: { - add_16_bit(personality, instructions, o1_reg_num, static_cast(to_int(o2.value))); + add_16_bit(personality, instructions, o1_reg_num, o2.value); return; } @@ -934,7 +963,7 @@ std::vector run(const Personality &personality, std::istream &input, co }; const auto parse_string = [&](const auto &string) { - std::stringstream ss{std::string(string)}; + std::stringstream ss{ std::string(string) }; parse_stream(ss); }; @@ -944,9 +973,7 @@ std::vector run(const Personality &personality, std::istream &input, co return instruction.line_text.find("__mulhi3") != std::string::npos; }); - if (needs_mulhi3) { - parse_string(__mulhi3); - } + if (needs_mulhi3) { parse_string(__mulhi3); } std::set labels; @@ -987,11 +1014,10 @@ std::vector run(const Personality &personality, std::istream &input, co // std::end(newl)); const auto new_label = [](auto label) -> std::string { - if (label[0] == '.') { - label.erase(0,1); - } + if (label[0] == '.') { label.erase(0, 1); } - for (auto &c : label) { if (c == '.') { c = '_'; } + for (auto &c : label) { + if (c == '.') { c = '_'; } } return label; @@ -1100,7 +1126,7 @@ int main(const int argc, const char **argv) std::filesystem::path filename{}; Target target{ Target::C64 }; - bool optimize{true}; + bool optimize{ true }; app.add_option("-f,--file", filename, "C++ file to compile")->required(true); app.add_option("-t,--target", target, "6502 - based system to target") @@ -1111,9 +1137,7 @@ int main(const int argc, const char **argv) app.add_option("-O", optimization_level, "Optimization level to pass to GCC instance") ->required(true) ->check(CLI::IsMember({ "s", "0", "1", "2", "3" })); - app.add_flag("--optimize", optimize, "Enable optimization of 6502 generated assembly") - ->default_val(true); - + app.add_flag("--optimize", optimize, "Enable optimization of 6502 generated assembly")->default_val(true); CLI11_PARSE(app, argc, argv) @@ -1132,14 +1156,49 @@ int main(const int argc, const char **argv) const auto mos6502_output_file = make_output_file_name(filename, "6502.asm"); 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 += " -fgcse-after-reload"; +// disabled_optimizations += " -fipa-cp-clone"; +// disabled_optimizations += " -floop-interchange"; +// disabled_optimizations += " -floop-unroll-and-jam"; +// disabled_optimizations += " -fpeel-loops"; +// disabled_optimizations += " -fpredictive-commoning"; +// disabled_optimizations += " -fsplit-loops"; +// disabled_optimizations += " -fsplit-paths"; +// disabled_optimizations += " -ftree-loop-distribution"; +// disabled_optimizations += " -ftree-loop-vectorize"; +// disabled_optimizations += " -ftree-partial-pre"; +// disabled_optimizations += " -ftree-slp-vectorize"; +// disabled_optimizations += " -funswitch-loops"; +// disabled_optimizations += " -fvect-cost-model=dynamic"; +// disabled_optimizations += " -fversion-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 " - "-mmcu={avr} -O{optimization} {include_dirs} {infile}", + "-mmcu={avr} -O{optimization} {disabled_optimizations} {include_dirs} {infile}", fmt::arg("outfile", avr_output_file.generic_string()), fmt::arg("warning_flags", warning_flags), fmt::arg("avr", avr), fmt::arg("optimization", optimization_level), fmt::arg("include_dirs", include_directories), + fmt::arg("disabled_optimizations", disabled_optimizations), fmt::arg("infile", filename.generic_string())); spdlog::info("Executing gcc: `{}`", gcc_command);