Better label handling

This commit is contained in:
Jason Turner 2021-05-27 08:31:02 -06:00
parent 949e118ef7
commit 8b159faa59
4 changed files with 166 additions and 59 deletions

View File

@ -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<uint8_t *>(&memory_loc(start)), str.data(), str.size());
std::copy(str.begin(), str.end(), &memory_loc(start));
// std::memcpy(const_cast<uint8_t *>(&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<std::uint8_t Width, std::uint8_t Height>
struct Map {
std::string_view name;
Graphic<Width, Height> layout;
std::span<const Map_Action> 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<const Map_Action>{}
};
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<const Map_Action>(begin(overview_actions), end(overview_actions))
};
cls();
poke(53280, 0);
poke(53281, 0);
static constexpr std::array<void (*)(std::uint8_t, std::uint8_t), 4> tile_types{
static constexpr std::array<void (*)(std::uint8_t, std::uint8_t), 7> 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();
}

View File

@ -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
)";

View File

@ -285,13 +285,15 @@ bool optimize(std::vector<mos6502> &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

View File

@ -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<mos6502> &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<mos6502> &instructions, int reg, const std::string_view value)
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::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<R"(\s*.word\s*gs\((.*)\))">;
const auto matcher = ctre::match<R"(\s*.word\s*(.*))">;
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<mos6502> 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<std::string> labels;
@ -995,13 +999,15 @@ std::vector<mos6502> 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<R"(\s*.word\s*gs\((.*)\))">;
const auto matcher = ctre::match<R"(\s*.word\s*(.*))">;
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<mos6502> run(const Personality &personality, std::istream &input, co
const auto new_labels = [&used_labels]() {
std::map<std::string, std::string> 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<mos6502> run(const Personality &personality, std::istream &input, co
}
}
if (i.type == ASMLine::Type::Directive) {
const auto matcher = ctre::match<R"(\s*.word\s*(.*))">;
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<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 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 "