1
0
mirror of https://github.com/lefticus/6502-cpp.git synced 2024-12-27 03:31:52 +00:00

Presentation code working

This commit is contained in:
Jason Turner 2021-08-31 17:57:08 -06:00
parent bda3c6a9fc
commit f410dfd38e
7 changed files with 227 additions and 102 deletions

View File

@ -1,7 +1,8 @@
#include <cstdint>
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 };
}

View File

@ -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

View File

@ -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<std::uint16_t>(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<std::uint16_t>(0xD800 + color_loc + offset), static_cast<std::uint8_t>(color));
}
}
static constexpr auto load_charset(const std::span<const std::uint8_t, 256 * 8> &bits)
{
std::array<petscii::Graphic<geometry::size{ 8, 8 }>, 256> results{};
for (std::size_t idx = 0; idx < 256; ++idx) {
petscii::Graphic<geometry::size{ 8, 8 }> 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<geometry::size Size> static constexpr auto from_pixels_to_petscii(const petscii::Graphic<Size> &pixels)
{
@ -228,44 +193,6 @@ template<geometry::size Size> static constexpr auto from_pixels_to_petscii(const
return result;
}
template<geometry::size Size> static constexpr auto from_pixels_to_2x2(const petscii::Graphic<Size> &pixels)
{
petscii::Graphic<geometry::size{ Size.width / 2, Size.height / 2 }> result{};
using GlyphType = std::pair<petscii::Graphic<geometry::size{ 2, 2 }>, std::uint8_t>;
constexpr std::array<GlyphType, 17> 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<geometry::size Size> struct SimpleSprite
{
geometry::point location{};

View File

@ -2,6 +2,7 @@
#define INC_6502_C_GEOMETRY_HPP
#include <cstdint>
#include <compare>
namespace geometry {
struct point

View File

@ -4,6 +4,7 @@
#include "geometry.hpp"
#include <algorithm>
#include <array>
#include <span>
namespace petscii {
@ -40,7 +41,7 @@ template<geometry::size size_> 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<geometry::size size_> 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<std::size_t Size> constexpr auto PETSCII(const char (&value)[Size]) noexcept
template<std::size_t Size> consteval auto PETSCII2(const char (&value)[Size]) noexcept
{
std::array<char, Size - 1> result{};
std::transform(std::begin(value), std::prev(std::end(value)), std::begin(result), charToPETSCII2);
return result;
}
template<std::size_t Size> consteval auto PETSCII(const char (&value)[Size]) noexcept
{
std::array<char, Size - 1> result{};
std::transform(std::begin(value), std::prev(std::end(value)), std::begin(result), charToPETSCII);
return result;
}
static constexpr auto load_charset(std::span<const std::uint8_t, 256 * 8> bits)
{
std::array<petscii::Graphic<geometry::size{ 8, 8 }>, 256> results{};
for (std::size_t idx = 0; idx < 256; ++idx) {
petscii::Graphic<geometry::size{ 8, 8 }> 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<geometry::size Size> static constexpr auto from_pixels_to_2x2(const petscii::Graphic<Size> &pixels)
{
petscii::Graphic<geometry::size{ Size.width / 2, Size.height / 2 }> result{};
using GlyphType = std::pair<petscii::Graphic<geometry::size{ 2, 2 }>, std::uint8_t>;
constexpr std::array<GlyphType, 17> 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<std::uint8_t>(x / 2), static_cast<std::uint8_t>(y / 2)}] = glyph.second;
break;// go to next Y, we found our match
}
}
}
}
return result;
}
}// namespace petscii

View File

@ -2,7 +2,10 @@
#define INC_6502_C_VICII_HPP
#include "6502.hpp"
#include "geometry.hpp"
#include <cstdint>
#include <algorithm>
#include <iterator>
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<std::uint16_t>(location.y * 40 + location.x);
const auto start = static_cast<std::uint16_t>(0x400 + offset);
@ -37,20 +40,44 @@ static void putc(geometry::point location, std::uint8_t c, Colors color)
mos6502::poke(offset + 0xD800, static_cast<std::uint8_t>(color));
}
static std::uint8_t getc(geometry::point location)
static inline std::uint8_t getc(geometry::point location)
{
const auto start = static_cast<std::uint16_t>(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<std::uint16_t>(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<std::uint8_t>(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<std::uint8_t>(color));
}
static inline void puts(const geometry::point loc, const auto &range, const vicii::Colors color = vicii::Colors::white)
{
const auto offset = static_cast<std::uint16_t>(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<std::uint16_t>(0xD800 + color_loc + offset), static_cast<std::uint8_t>(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<std::uint8_t>(0xFF & (value >> 8)), color);
put_hex(location + geometry::point{ 2, 0 }, static_cast<std::uint8_t>(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<Colors>(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);
}

View File

@ -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<mos6502> &inst
instructions.emplace_back(ASMLine::Type::Label, skip_high_byte_label);
}
void decrement_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg)
{
subtract_16_bit(personality, instructions, reg, 1);
}
void translate_instruction(const Personality &personality,
std::vector<mos6502> &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<std::uint8_t>(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<R"(\s*.word\s*(.*))">;
@ -1129,17 +1200,19 @@ std::vector<mos6502> 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<R"(([A-Za-z0-9.]+).*)">;
const auto label_matcher = ctre::match<R"(-?\(?([A-Za-z0-9.]+).*)">;
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<std::size_t>(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<std::string> 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()));