mirror of
https://github.com/lefticus/6502-cpp.git
synced 2024-12-22 01:30:03 +00:00
Fix parsing of literal expressions for adiw/subw
This commit is contained in:
parent
1f03d18d5e
commit
cc08629435
@ -24,6 +24,28 @@ static void decrement_border_color() { --memory_loc(0xd020); }
|
|||||||
|
|
||||||
static void increment_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() {
|
static bool joystick_down() {
|
||||||
uint8_t joystick_state = peek(0xDC00);
|
uint8_t joystick_state = peek(0xDC00);
|
||||||
return (joystick_state & 2) == 0;
|
return (joystick_state & 2) == 0;
|
||||||
@ -287,6 +309,11 @@ struct SimpleSprite
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// helper type for the visitor #4
|
||||||
|
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||||
|
// explicit deduction guide (not needed as of C++20)
|
||||||
|
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
|
|
||||||
struct Screen
|
struct Screen
|
||||||
{
|
{
|
||||||
void load(std::uint8_t x, std::uint8_t y, auto &s) {
|
void load(std::uint8_t x, std::uint8_t y, auto &s) {
|
||||||
@ -413,9 +440,15 @@ int main() {
|
|||||||
return endurance * 5;
|
return endurance * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JoyStickStateChanged
|
struct JoyStick1StateChanged
|
||||||
{
|
{
|
||||||
std::uint8_t state;
|
Joystick state;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct JoyStick2StateChanged
|
||||||
|
{
|
||||||
|
Joystick state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimeElapsed
|
struct TimeElapsed
|
||||||
@ -423,16 +456,16 @@ int main() {
|
|||||||
Clock::milliseconds us;
|
Clock::milliseconds us;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Event = std::variant<JoyStickStateChanged, TimeElapsed>;
|
using Event = std::variant<JoyStick2StateChanged, TimeElapsed>;
|
||||||
|
|
||||||
std::uint8_t last_joystick_state = peek(0xDC00);
|
std::uint8_t last_joystick_2_state = peek(0xDC00);
|
||||||
|
|
||||||
Event next_event() noexcept {
|
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) {
|
if (new_joystick_2_state != last_joystick_2_state) {
|
||||||
last_joystick_state = new_joystick_state;
|
last_joystick_2_state = new_joystick_2_state;
|
||||||
return JoyStickStateChanged{new_joystick_state};
|
return JoyStick2StateChanged{Joystick{new_joystick_2_state}};
|
||||||
}
|
}
|
||||||
|
|
||||||
return TimeElapsed{game_clock.restart()};
|
return TimeElapsed{game_clock.restart()};
|
||||||
@ -460,30 +493,35 @@ int main() {
|
|||||||
|
|
||||||
show_stats(game);
|
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) {
|
||||||
void operator()(const GameState::JoyStickStateChanged &e) {
|
if (e.state.up()) {
|
||||||
put_hex(36, 1, e.state);
|
--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::TimeElapsed &e) {
|
put_hex(36, 1, e.state.state);
|
||||||
|
},
|
||||||
|
[](const GameState::TimeElapsed &e) {
|
||||||
put_hex(36, 0, e.us.count());
|
put_hex(36, 0, e.us.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
HandleEvents eventHandler;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::visit(eventHandler, game.next_event());
|
std::visit(eventHandler, game.next_event());
|
||||||
|
|
||||||
screen.show(x++, 10, character);
|
|
||||||
|
|
||||||
if (x == 11) {
|
|
||||||
x = 10;
|
|
||||||
}
|
|
||||||
increment_border_color();
|
increment_border_color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +51,7 @@ std::string_view strip_gs(std::string_view s)
|
|||||||
{
|
{
|
||||||
const auto matcher = ctre::match<R"(gs\((.*)\))">;
|
const auto matcher = ctre::match<R"(gs\((.*)\))">;
|
||||||
|
|
||||||
if (const auto results = matcher(s); results) {
|
if (const auto results = matcher(s); results) { return results.get<1>(); }
|
||||||
return results.get<1>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -294,6 +292,21 @@ void fixup_16_bit_N_Z_flags(std::vector<mos6502> &instructions)
|
|||||||
instructions.emplace_back(ASMLine::Type::Directive, "; END remove if next is lda, bcc, bcs");
|
instructions.emplace_back(ASMLine::Type::Directive, "; END remove if next is lda, bcc, bcs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_16_bit(const Personality &personality, std::vector<mos6502> &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<mos6502> &instructions, int reg, const std::uint16_t value)
|
void add_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg, const std::uint16_t value)
|
||||||
{
|
{
|
||||||
instructions.emplace_back(mos6502::OpCode::clc);
|
instructions.emplace_back(mos6502::OpCode::clc);
|
||||||
@ -310,6 +323,25 @@ void add_16_bit(const Personality &personality, std::vector<mos6502> &instructio
|
|||||||
fixup_16_bit_N_Z_flags(instructions);
|
fixup_16_bit_N_Z_flags(instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void subtract_16_bit(const Personality &personality,
|
||||||
|
std::vector<mos6502> &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,
|
void subtract_16_bit(const Personality &personality,
|
||||||
std::vector<mos6502> &instructions,
|
std::vector<mos6502> &instructions,
|
||||||
int reg,
|
int reg,
|
||||||
@ -331,8 +363,7 @@ void subtract_16_bit(const Personality &personality,
|
|||||||
|
|
||||||
void increment_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg)
|
void increment_16_bit(const Personality &personality, std::vector<mos6502> &instructions, int reg)
|
||||||
{
|
{
|
||||||
std::string skip_high_byte_label =
|
std::string skip_high_byte_label = "skip_inc_high_byte_" + std::to_string(instructions.size());
|
||||||
"skip_inc_high_byte_" + std::to_string(instructions.size());
|
|
||||||
instructions.emplace_back(mos6502::OpCode::inc, personality.get_register(reg));
|
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::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));
|
||||||
@ -365,8 +396,6 @@ void translate_instruction(const Personality &personality,
|
|||||||
// sufficient
|
// sufficient
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
|
instructions.emplace_back(mos6502::OpCode::lda, personality.get_register(o1_reg_num));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
case AVR::OpCode::dec: instructions.emplace_back(mos6502::OpCode::dec, 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:
|
case AVR::OpCode::ldi:
|
||||||
@ -591,12 +620,12 @@ void translate_instruction(const Personality &personality,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case AVR::OpCode::sbiw: {
|
case AVR::OpCode::sbiw: {
|
||||||
subtract_16_bit(personality, instructions, o1_reg_num, static_cast<std::uint16_t>(to_int(o2.value)));
|
subtract_16_bit(personality, instructions, o1_reg_num, o2.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AVR::OpCode::adiw: {
|
case AVR::OpCode::adiw: {
|
||||||
add_16_bit(personality, instructions, o1_reg_num, static_cast<std::uint16_t>(to_int(o2.value)));
|
add_16_bit(personality, instructions, o1_reg_num, o2.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,9 +973,7 @@ std::vector<mos6502> run(const Personality &personality, std::istream &input, co
|
|||||||
return instruction.line_text.find("__mulhi3") != std::string::npos;
|
return instruction.line_text.find("__mulhi3") != std::string::npos;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (needs_mulhi3) {
|
if (needs_mulhi3) { parse_string(__mulhi3); }
|
||||||
parse_string(__mulhi3);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> labels;
|
std::set<std::string> labels;
|
||||||
|
|
||||||
@ -987,11 +1014,10 @@ std::vector<mos6502> run(const Personality &personality, std::istream &input, co
|
|||||||
// std::end(newl));
|
// std::end(newl));
|
||||||
|
|
||||||
const auto new_label = [](auto label) -> std::string {
|
const auto new_label = [](auto label) -> std::string {
|
||||||
if (label[0] == '.') {
|
if (label[0] == '.') { label.erase(0, 1); }
|
||||||
label.erase(0,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &c : label) { if (c == '.') { c = '_'; }
|
for (auto &c : label) {
|
||||||
|
if (c == '.') { c = '_'; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return label;
|
return label;
|
||||||
@ -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")
|
app.add_option("-O", optimization_level, "Optimization level to pass to GCC instance")
|
||||||
->required(true)
|
->required(true)
|
||||||
->check(CLI::IsMember({ "s", "0", "1", "2", "3" }));
|
->check(CLI::IsMember({ "s", "0", "1", "2", "3" }));
|
||||||
app.add_flag("--optimize", optimize, "Enable optimization of 6502 generated assembly")
|
app.add_flag("--optimize", optimize, "Enable optimization of 6502 generated assembly")->default_val(true);
|
||||||
->default_val(true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CLI11_PARSE(app, argc, argv)
|
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 mos6502_output_file = make_output_file_name(filename, "6502.asm");
|
||||||
const auto program_output_file = make_output_file_name(filename, "prg");
|
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(
|
const std::string gcc_command = fmt::format(
|
||||||
"avr-gcc -fverbose-asm -c -o {outfile} -S {warning_flags} -std=c++20 -mtiny-stack "
|
"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("outfile", avr_output_file.generic_string()),
|
||||||
fmt::arg("warning_flags", warning_flags),
|
fmt::arg("warning_flags", warning_flags),
|
||||||
fmt::arg("avr", avr),
|
fmt::arg("avr", avr),
|
||||||
fmt::arg("optimization", optimization_level),
|
fmt::arg("optimization", optimization_level),
|
||||||
fmt::arg("include_dirs", include_directories),
|
fmt::arg("include_dirs", include_directories),
|
||||||
|
fmt::arg("disabled_optimizations", disabled_optimizations),
|
||||||
fmt::arg("infile", filename.generic_string()));
|
fmt::arg("infile", filename.generic_string()));
|
||||||
|
|
||||||
spdlog::info("Executing gcc: `{}`", gcc_command);
|
spdlog::info("Executing gcc: `{}`", gcc_command);
|
||||||
|
Loading…
Reference in New Issue
Block a user