From f410dfd38e9e9d4a984611962bad152ee5ce2bc4 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 31 Aug 2021 17:57:08 -0600 Subject: [PATCH] Presentation code working --- examples/simple_game/chargen.hpp | 10 ++- examples/simple_game/commodore64.hpp | 3 + examples/simple_game/game.cpp | 73 ------------------ examples/simple_game/geometry.hpp | 1 + examples/simple_game/petscii.hpp | 86 ++++++++++++++++++++- examples/simple_game/vicii.hpp | 47 +++++++++--- src/6502-c++.cpp | 109 +++++++++++++++++++++++---- 7 files changed, 227 insertions(+), 102 deletions(-) diff --git a/examples/simple_game/chargen.hpp b/examples/simple_game/chargen.hpp index 8e060b3..b5a9efc 100644 --- a/examples/simple_game/chargen.hpp +++ b/examples/simple_game/chargen.hpp @@ -1,7 +1,8 @@ #include -constexpr std::uint8_t uppercase[] = { - 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, +namespace petscii { +constexpr static std::uint8_t uppercase[] = { +0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, 0x18, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, @@ -258,7 +259,8 @@ constexpr std::uint8_t uppercase[] = { 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, }; -constexpr std::uint8_t lowercase[] = { 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, +constexpr static std::uint8_t lowercase[] = { +0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00, @@ -514,3 +516,5 @@ constexpr std::uint8_t lowercase[] = { 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0 }; + +} diff --git a/examples/simple_game/commodore64.hpp b/examples/simple_game/commodore64.hpp index 6eb746f..919c1a8 100644 --- a/examples/simple_game/commodore64.hpp +++ b/examples/simple_game/commodore64.hpp @@ -20,6 +20,9 @@ struct Joystick [[nodiscard]] constexpr bool fire() const noexcept { return (state & 16) == 0; } [[nodiscard]] constexpr bool right() const noexcept { return (state & 8) == 0; } [[nodiscard]] constexpr bool down() const noexcept { return (state & 2) == 0; } + + [[nodiscard]] constexpr bool operator==(const Joystick &other) const = default; + [[nodiscard]] constexpr bool operator!=(const Joystick &other) const = default; }; struct Clock diff --git a/examples/simple_game/game.cpp b/examples/simple_game/game.cpp index bc10a3a..d8d9463 100644 --- a/examples/simple_game/game.cpp +++ b/examples/simple_game/game.cpp @@ -161,42 +161,7 @@ struct GameState } }; -static void puts(const geometry::point loc, const auto &range, const vicii::Colors color = vicii::Colors::white) -{ - const auto offset = static_cast(loc.y * 40 + loc.x); - const std::uint16_t start = 0x400 + offset; - std::copy(begin(range), end(range), &mos6502::memory_loc(start)); - - for (std::uint16_t color_loc = 0; color_loc < range.size(); ++color_loc) { - mos6502::poke(static_cast(0xD800 + color_loc + offset), static_cast(color)); - } -} - -static constexpr auto load_charset(const std::span &bits) -{ - std::array, 256> results{}; - - for (std::size_t idx = 0; idx < 256; ++idx) { - petscii::Graphic glyph{}; - - for (std::uint8_t row = 0; row < 8; ++row) { - const auto input_row = bits[idx * 8 + row]; - glyph[geometry::point{ 0, row }] = (0b1000'0000 & input_row) == 0 ? 0 : 1; - glyph[geometry::point{ 0, row }] = (0b0100'0000 & input_row) == 0 ? 0 : 1; - glyph[geometry::point{ 0, row }] = (0b0010'0000 & input_row) == 0 ? 0 : 1; - glyph[geometry::point{ 0, row }] = (0b0001'0000 & input_row) == 0 ? 0 : 1; - glyph[geometry::point{ 0, row }] = (0b0000'1000 & input_row) == 0 ? 0 : 1; - glyph[geometry::point{ 0, row }] = (0b0000'0100 & input_row) == 0 ? 0 : 1; - glyph[geometry::point{ 0, row }] = (0b0000'0010 & input_row) == 0 ? 0 : 1; - glyph[geometry::point{ 0, row }] = (0b0000'0001 & input_row) == 0 ? 0 : 1; - } - - results[idx] = glyph; - } - - return results; -} template static constexpr auto from_pixels_to_petscii(const petscii::Graphic &pixels) { @@ -228,44 +193,6 @@ template static constexpr auto from_pixels_to_petscii(const return result; } - -template static constexpr auto from_pixels_to_2x2(const petscii::Graphic &pixels) -{ - petscii::Graphic result{}; - - using GlyphType = std::pair, std::uint8_t>; - constexpr std::array lookup_map{ GlyphType{ { 0, 0, 0, 0 }, 32 }, - GlyphType{ { 1, 0, 0, 0 }, 126 }, - GlyphType{ { 0, 1, 0, 0 }, 124 }, - GlyphType{ { 1, 1, 0, 0 }, 226 }, - GlyphType{ { 0, 0, 1, 0 }, 123 }, - GlyphType{ { 1, 0, 1, 0 }, 97 }, - GlyphType{ { 0, 1, 1, 0 }, 255 }, - GlyphType{ { 1, 1, 1, 0 }, 236 }, - GlyphType{ { 0, 0, 0, 1 }, 108 }, - GlyphType{ { 1, 0, 0, 1 }, 127 }, - GlyphType{ { 0, 1, 0, 1 }, 225 }, - GlyphType{ { 1, 1, 0, 1 }, 251 }, - GlyphType{ { 0, 0, 1, 1 }, 98 }, - GlyphType{ { 1, 0, 1, 1 }, 252 }, - GlyphType{ { 0, 1, 1, 1 }, 254 }, - GlyphType{ { 1, 1, 1, 1 }, 160 } }; - - - for (uint8_t x = 0; x < pixels.width(); x += 2) { - for (uint8_t y = 0; y < pixels.height(); y += 2) { - for (const auto &glyph : lookup_map) { - if (pixels.match(glyph.first, x, y)) { - result(x / 2, y / 2) = glyph.second; - break;// go to next Y, we found our match - } - } - } - } - - return result; -} - template struct SimpleSprite { geometry::point location{}; diff --git a/examples/simple_game/geometry.hpp b/examples/simple_game/geometry.hpp index a0844a5..531e82d 100644 --- a/examples/simple_game/geometry.hpp +++ b/examples/simple_game/geometry.hpp @@ -2,6 +2,7 @@ #define INC_6502_C_GEOMETRY_HPP #include +#include namespace geometry { struct point diff --git a/examples/simple_game/petscii.hpp b/examples/simple_game/petscii.hpp index 2f83e03..766af8c 100644 --- a/examples/simple_game/petscii.hpp +++ b/examples/simple_game/petscii.hpp @@ -4,6 +4,7 @@ #include "geometry.hpp" #include #include +#include namespace petscii { @@ -40,7 +41,7 @@ template struct Graphic constexpr bool match(const auto &graphic, const geometry::point p) const { - return match_count(graphic, p) == (graphic.width() * graphic.height()); + return match_count(graphic, p) == (graphic.size().width * graphic.size().height); } }; @@ -51,18 +52,99 @@ template struct ColoredGraphic }; +[[nodiscard]] constexpr char charToPETSCII2(char c) noexcept +{ + if (c >= 'a' && c <= 'z') { return c - 'a' + 1; } + if (c >= 'A' && c <= 'Z') { return c - 'A' + 65; } + if (c == '@') { return 0; } + return c; +} + + [[nodiscard]] constexpr char charToPETSCII(char c) noexcept { + if (c == '@') { return 0; } if (c >= 'A' && c <= 'Z') { return c - 'A' + 1; } return c; } -template constexpr auto PETSCII(const char (&value)[Size]) noexcept +template consteval auto PETSCII2(const char (&value)[Size]) noexcept +{ + std::array result{}; + std::transform(std::begin(value), std::prev(std::end(value)), std::begin(result), charToPETSCII2); + return result; +} +template consteval auto PETSCII(const char (&value)[Size]) noexcept { std::array result{}; std::transform(std::begin(value), std::prev(std::end(value)), std::begin(result), charToPETSCII); return result; } + +static constexpr auto load_charset(std::span bits) +{ + std::array, 256> results{}; + + for (std::size_t idx = 0; idx < 256; ++idx) { + petscii::Graphic glyph{}; + + for (std::uint8_t row = 0; row < 8; ++row) { + const auto input_row = bits[idx * 8 + row]; + glyph[geometry::point{ 0, row }] = (0b1000'0000 & input_row) == 0 ? 0 : 1; + glyph[geometry::point{ 1, row }] = (0b0100'0000 & input_row) == 0 ? 0 : 1; + glyph[geometry::point{ 2, row }] = (0b0010'0000 & input_row) == 0 ? 0 : 1; + glyph[geometry::point{ 3, row }] = (0b0001'0000 & input_row) == 0 ? 0 : 1; + glyph[geometry::point{ 4, row }] = (0b0000'1000 & input_row) == 0 ? 0 : 1; + glyph[geometry::point{ 5, row }] = (0b0000'0100 & input_row) == 0 ? 0 : 1; + glyph[geometry::point{ 6, row }] = (0b0000'0010 & input_row) == 0 ? 0 : 1; + glyph[geometry::point{ 7, row }] = (0b0000'0001 & input_row) == 0 ? 0 : 1; + } + + results[idx] = glyph; + } + + return results; +} + +template static constexpr auto from_pixels_to_2x2(const petscii::Graphic &pixels) +{ + petscii::Graphic result{}; + + using GlyphType = std::pair, std::uint8_t>; + constexpr std::array lookup_map{ GlyphType{ { 0, 0, 0, 0 }, 32 }, + GlyphType{ { 1, 0, 0, 0 }, 126 }, + GlyphType{ { 0, 1, 0, 0 }, 124 }, + GlyphType{ { 1, 1, 0, 0 }, 226 }, + GlyphType{ { 0, 0, 1, 0 }, 123 }, + GlyphType{ { 1, 0, 1, 0 }, 97 }, + GlyphType{ { 0, 1, 1, 0 }, 255 }, + GlyphType{ { 1, 1, 1, 0 }, 236 }, + GlyphType{ { 0, 0, 0, 1 }, 108 }, + GlyphType{ { 1, 0, 0, 1 }, 127 }, + GlyphType{ { 0, 1, 0, 1 }, 225 }, + GlyphType{ { 1, 1, 0, 1 }, 251 }, + GlyphType{ { 0, 0, 1, 1 }, 98 }, + GlyphType{ { 1, 0, 1, 1 }, 252 }, + GlyphType{ { 0, 1, 1, 1 }, 254 }, + GlyphType{ { 1, 1, 1, 1 }, 160 } }; + + + for (uint8_t x = 0; x < pixels.size().width; x += 2) { + for (uint8_t y = 0; y < pixels.size().height; y += 2) { + for (const auto &glyph : lookup_map) { + if (pixels.match(glyph.first, {x, y})) { + result[geometry::point{static_cast(x / 2), static_cast(y / 2)}] = glyph.second; + break;// go to next Y, we found our match + } + } + } + } + + return result; +} + + + }// namespace petscii diff --git a/examples/simple_game/vicii.hpp b/examples/simple_game/vicii.hpp index 133180b..d87c38e 100644 --- a/examples/simple_game/vicii.hpp +++ b/examples/simple_game/vicii.hpp @@ -2,7 +2,10 @@ #define INC_6502_C_VICII_HPP #include "6502.hpp" +#include "geometry.hpp" #include +#include +#include namespace vicii { enum struct Colors : std::uint8_t { @@ -29,7 +32,7 @@ enum struct Colors : std::uint8_t { // static void increment_border_color() { mos6502::poke(0xd020, mos6502::peek(0xd020) + 1); } -static void putc(geometry::point location, std::uint8_t c, Colors color) +static inline void putc(geometry::point location, std::uint8_t c, Colors color) { const auto offset = static_cast(location.y * 40 + location.x); const auto start = static_cast(0x400 + offset); @@ -37,20 +40,44 @@ static void putc(geometry::point location, std::uint8_t c, Colors color) mos6502::poke(offset + 0xD800, static_cast(color)); } -static std::uint8_t getc(geometry::point location) +static inline std::uint8_t getc(geometry::point location) { const auto start = static_cast(0x400 + (location.y * 40 + location.x)); return mos6502::peek(start); } -static void invertc(geometry::point location) +static inline void invertc(geometry::point location) { const auto start = static_cast(0x400 + (location.y * 40 + location.x)); mos6502::memory_loc(start) += 128; } +static inline void set_background(const vicii::Colors color) { + mos6502::poke(53280, static_cast(color)); +} -static void put_hex(geometry::point start, uint8_t value, Colors color) +static inline void set_border(const vicii::Colors color) { + mos6502::poke(53281, static_cast(color)); +} + + +static inline void puts(const geometry::point loc, const auto &range, const vicii::Colors color = vicii::Colors::white) +{ + const auto offset = static_cast(loc.y * 40 + loc.x); + + const std::uint16_t start = 0x400 + offset; + + using namespace std; + + std::copy(begin(range), end(range), &mos6502::memory_loc(start)); + + for (std::uint16_t color_loc = 0; color_loc < size(range); ++color_loc) { + mos6502::poke(static_cast(0xD800 + color_loc + offset), static_cast(color)); + } +} + + +static inline void put_hex(geometry::point start, uint8_t value, Colors color) { const auto put_nibble = [color](geometry::point location, std::uint8_t nibble) { if (nibble <= 9) { @@ -64,18 +91,18 @@ static void put_hex(geometry::point start, uint8_t value, Colors color) put_nibble(start , 0xF & (value >> 4)); } -static void put_hex(geometry::point location, std::uint16_t value, Colors color) +static inline void put_hex(geometry::point location, std::uint16_t value, Colors color) { put_hex(location, static_cast(0xFF & (value >> 8)), color); put_hex(location + geometry::point{ 2, 0 }, static_cast(0xFF & value), color); } -static void put_graphic(geometry::point location, const auto &graphic) +static inline void put_graphic(geometry::point location, const auto &graphic) { for (const auto &p : graphic.size()) { putc(p + location, graphic[p], Colors::white); } } -static void put_graphic(geometry::point location, const auto &graphic) requires requires { graphic.colors[{0, 0}]; } +static inline void put_graphic(geometry::point location, const auto &graphic) requires requires { graphic.colors[{0, 0}]; } { for (const auto &p : graphic.data.size()) { putc(p + location, graphic.data[p], static_cast(graphic.colors[p])); @@ -83,7 +110,7 @@ static void put_graphic(geometry::point location, const auto &graphic) requires } -static void cls() +static inline void cls() { for (std::uint16_t i = 0x400; i < 0x400 + 1000; ++i) { mos6502::poke(i, 32); } } @@ -135,7 +162,7 @@ static void draw_hline(geometry::point begin, const geometry::point end, Colors } } -static void draw_box(geometry::rect geo, Colors color) +static inline void draw_box(geometry::rect geo, Colors color) { putc(geo.top_left(), 85, color); putc(geo.top_right(), 73, color); @@ -149,7 +176,7 @@ static void draw_box(geometry::rect geo, Colors color) draw_vline(geo.top_right() + geometry::point{ 0, 1 }, geo.bottom_right(), color); } -void clear(geometry::rect box, Colors color) { +static inline void clear(geometry::rect box, Colors color) { for (const auto &p : box.size()) { putc(p + box.top_left(), ' ', color); } diff --git a/src/6502-c++.cpp b/src/6502-c++.cpp index 2b8ad9d..4911819 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -92,6 +92,7 @@ struct AVR : ASMLine adiw, add, andi, + asr, breq, brge, @@ -129,6 +130,7 @@ struct AVR : ASMLine nop, OR, + ori, out, pop, @@ -182,6 +184,7 @@ struct AVR : ASMLine if (o == "lds") { return OpCode::lds; } if (o == "lsr") { return OpCode::lsr; } if (o == "andi") { return OpCode::andi; } + if (o == "asr") { return OpCode::asr; } if (o == "eor") { return OpCode::eor; } if (o == "sbrc") { return OpCode::sbrc; } if (o == "rjmp") { return OpCode::rjmp; } @@ -213,6 +216,7 @@ struct AVR : ASMLine if (o == "brge") { return OpCode::brge; } if (o == "brlt") { return OpCode::brlt; } if (o == "or") { return OpCode::OR; } + if (o == "ori") { return OpCode::ori; } } } throw std::runtime_error(fmt::format("Unknown opcode: {}", o)); @@ -395,6 +399,12 @@ void increment_16_bit(const Personality &personality, std::vector &inst instructions.emplace_back(ASMLine::Type::Label, skip_high_byte_label); } +void decrement_16_bit(const Personality &personality, std::vector &instructions, int reg) +{ + subtract_16_bit(personality, instructions, reg, 1); +} + + void translate_instruction(const Personality &personality, std::vector &instructions, const AVR::OpCode op, @@ -421,6 +431,12 @@ void translate_instruction(const Personality &personality, instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); return; } + case AVR::OpCode::ori: { + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::ORA, Operand(o2.type, fixup_8bit_literal(o2.value))); + instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num)); + return; + } case AVR::OpCode::jmp: instructions.emplace_back(mos6502::OpCode::jmp, o1); return; case AVR::OpCode::tst: { // just an lda will set the relevant flags that the tst operation sets, so I think this is @@ -617,6 +633,13 @@ void translate_instruction(const Personality &personality, increment_16_bit(personality, instructions, AVR::get_register_number(o1.value[0])); return; } + if (o1.value == "-Z" || o1.value == "-Y" || o1.value == "-X") { + decrement_16_bit(personality, instructions, AVR::get_register_number(o1.value[1])); + indirect_store(instructions, + personality.get_register(o2_reg_num).value, + personality.get_register(AVR::get_register_number(o1.value[1])).value); + return; + } throw std::runtime_error("Unhandled st"); } case AVR::OpCode::lds: { @@ -628,6 +651,12 @@ void translate_instruction(const Personality &personality, instructions.emplace_back(mos6502::OpCode::lsr, personality.get_register(o1_reg_num)); return; } + case AVR::OpCode::asr: { + instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); + instructions.emplace_back(mos6502::OpCode::asl); + instructions.emplace_back(mos6502::OpCode::ror, personality.get_register(o1_reg_num)); + return; + } case AVR::OpCode::andi: { instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num)); instructions.emplace_back(mos6502::OpCode::AND, Operand(o2.type, fixup_8bit_literal(o2.value))); @@ -670,6 +699,9 @@ void translate_instruction(const Personality &personality, if (o1.value == "0b") { instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, "memcpy_0")); return; + } else if (o1.value == "1b") { + instructions.emplace_back(mos6502::OpCode::bne, Operand(Operand::Type::literal, "mul2_1")); + return; } else if (o1.value == ".+2") { // assumes 6502 'borrow' for Carry flag instead of carry, so bcc instead of bcs std::string new_label_name = "skip_next_instruction_" + std::to_string(instructions.size()); @@ -869,13 +901,52 @@ void to_mos6502(const Personality &personality, const AVR &from_instruction, std case ASMLine::Type::Label: if (from_instruction.text == "0") { instructions.emplace_back(from_instruction.type, "-memcpy_0"); + } else if (from_instruction.text == "1") { + instructions.emplace_back(from_instruction.type, "-mul2_1"); } else { instructions.emplace_back(from_instruction.type, from_instruction.text); } return; case ASMLine::Type::Directive: - if (from_instruction.text.starts_with(".string")) { - instructions.emplace_back(ASMLine::Type::Directive, ".asc " + from_instruction.text.substr(7)); + if (from_instruction.text.starts_with(".string") || from_instruction.text.starts_with(".ascii")) { + const auto &text = from_instruction.text; + const auto start = [=]() -> std::size_t { + if (text.starts_with(".string")) { + return 9; + } else { + return 8; + } + }(); + + const auto isdigit = [](char c){ + return c <= '9' && c >= '0'; + }; + + for (std::size_t pos = start; text[pos] != '"'; ++pos) { + if (text[pos] != '\\') { + instructions.emplace_back(ASMLine::Type::Directive, fmt::format(".byt ${:02x}", static_cast(text[pos]))); + } else { + if (text[pos+1] == 'f') { + instructions.emplace_back(ASMLine::Type::Directive, fmt::format(".byt ${:02x}", 014)); + ++pos; + } else if (isdigit(text[pos+1]) && isdigit(text[pos+2]) && isdigit(text[pos+3])) { + std::string octal = "0"; + octal += text[pos+1]; + octal += text[pos+2]; + octal += text[pos+3]; + instructions.emplace_back(ASMLine::Type::Directive, fmt::format(".byt ${:02x}", std::stoi(octal, nullptr, 8))); + pos += 3; + } else { + spdlog::error( + "[{}]: Unhandled .string escape: '{}': {}", from_instruction.line_num, from_instruction.line_text, text[pos+1]); + + } + } + } + + if (text.starts_with(".string")) { + instructions.emplace_back(ASMLine::Type::Directive, ".byt 0"); // terminating byte + } } else if (from_instruction.text.starts_with(".word")) { const auto matcher = ctre::match; @@ -1129,17 +1200,19 @@ std::vector run(const Personality &personality, std::istream &input, co if (i.operand2.value.starts_with("lo8(") || i.operand2.value.starts_with("hi8(")) { const auto lo_hi_operand = strip_lo_hi(i.operand2.value); - const auto label_matcher = ctre::match; + 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 start = std::distance(std::string_view{i.operand2.value}.begin(), potential_label.begin()); + spdlog::trace("Label matched: '{}'", potential_label); 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); } + if (itr1 != new_labels.end()) { i.operand2.value.replace(static_cast(start), potential_label.size(), itr1->second); } + spdlog::trace("New statement: '{}'", i.operand2.value); } } - if (const auto plus = i.operand1.value.find('+'); plus != std::string::npos) - { + if (const auto plus = i.operand1.value.find('+'); plus != std::string::npos) { const auto str = i.operand1.value.substr(0, plus); const auto itr1 = new_labels.find(str); if (itr1 != new_labels.end()) { i.operand1.value.replace(0, plus, itr1->second); } @@ -1232,23 +1305,31 @@ int main(const int argc, const char **argv) Target target{ Target::C64 }; bool optimize{ true }; - app.add_option("-f,--file", filename, "C++ file to compile")->required(true); + app.add_option("filename", filename, "C++ file to compile")->required(true); app.add_option("-t,--target", target, "6502 - based system to target") ->required(true) ->transform(CLI::CheckedTransformer(targets, CLI::ignore_case)); std::string optimization_level; app.add_option("-O", optimization_level, "Optimization level to pass to GCC instance") - ->required(true) - ->check(CLI::IsMember({ "s", "0", "1", "2", "3" })); + ->required(false) + ->check(CLI::IsMember({ "s", "0", "1", "2", "3" })) + ->default_val("1"); + app.add_flag("--optimize", optimize, "Enable optimization of 6502 generated assembly")->default_val(true); + std::vector include_paths; + app.add_option("-I", include_paths, "Extra include paths to pass to GCC instance") + ->required(false) + ->expected(1) + ->take_all(); CLI11_PARSE(app, argc, argv) + - const std::string_view include_directories = "-I ~/avr-libstdcpp/include/"; - const std::string_view warning_flags = "-Wall -Wextra"; + include_paths.insert(include_paths.begin(), "~/avr-libstdcpp/include"); + const std::string_view warning_flags = "-Wall -Wextra -Wconversion"; const std::string_view avr = "avr3"; const auto make_output_file_name = [](auto input_filename, const auto &new_extension) { @@ -1280,13 +1361,13 @@ int main(const int argc, const char **argv) */ 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} {disabled_optimizations} {include_dirs} {infile}", + "avr-gcc -fverbose-asm -c -o {outfile} -S {warning_flags} -std=c++20 -mtiny-stack -fconstexpr-ops-limit=333554432 " + "-mmcu={avr} -O{optimization} {disabled_optimizations} -I {user_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("user_include_dirs", fmt::join(include_paths, " -I ")), fmt::arg("disabled_optimizations", disabled_optimizations), fmt::arg("infile", filename.generic_string()));