mirror of
https://github.com/lefticus/6502-cpp.git
synced 2025-02-06 14:30:11 +00:00
Fix up some optimizer passes
This commit is contained in:
parent
28ebf888e3
commit
e7a3db9dda
44
examples/hello_commodore.cpp
Normal file
44
examples/hello_commodore.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
|
||||
enum Colors : uint8_t { WHITE = 0x01 };
|
||||
|
||||
static volatile uint8_t &memory_loc(const uint16_t loc) {
|
||||
return *reinterpret_cast<volatile uint8_t *>(loc);
|
||||
}
|
||||
|
||||
static void poke(const uint16_t loc, const uint8_t value) {
|
||||
memory_loc(loc) = value;
|
||||
}
|
||||
|
||||
static std::uint8_t peek(const std::uint16_t loc) { return memory_loc(loc); }
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::uint8_t x = 0;
|
||||
std::uint8_t y = 0;
|
||||
|
||||
while (true) {
|
||||
puts(x, y, "hello commodore!");
|
||||
x += 3;
|
||||
++y;
|
||||
if (x > 26) {
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (y>25) {
|
||||
y = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
141
examples/test_lambda.cpp
Normal file
141
examples/test_lambda.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
|
||||
enum Colors : uint8_t { WHITE = 0x01 };
|
||||
|
||||
static volatile uint8_t &memory_loc(const uint16_t loc) {
|
||||
return *reinterpret_cast<volatile uint8_t *>(loc);
|
||||
}
|
||||
|
||||
static void poke(const uint16_t loc, const uint8_t value) {
|
||||
memory_loc(loc) = value;
|
||||
}
|
||||
|
||||
static std::uint8_t peek(const std::uint16_t loc) { return memory_loc(loc); }
|
||||
|
||||
static void decrement_border_color() { --memory_loc(0xd020); }
|
||||
|
||||
static void increment_border_color() { ++memory_loc(0xd020); }
|
||||
|
||||
static bool joystick_down() {
|
||||
uint8_t joystick_state = peek(0xDC00);
|
||||
return (joystick_state & 2) == 0;
|
||||
}
|
||||
|
||||
void use_data(std::array<char, 1024> &data);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
template<std::uint8_t Width, std::uint8_t Height>
|
||||
struct Graphic
|
||||
{
|
||||
std::array<std::uint8_t, Width * Height> data;
|
||||
|
||||
static constexpr auto width() noexcept {
|
||||
return Width;
|
||||
}
|
||||
|
||||
static constexpr auto height() noexcept {
|
||||
return Height;
|
||||
}
|
||||
|
||||
constexpr Graphic() = default;
|
||||
|
||||
constexpr Graphic(std::array<uint8_t, Width * Height> data_) noexcept : data(data_) {}
|
||||
constexpr Graphic(std::initializer_list<uint8_t> data_) noexcept {
|
||||
std::copy(begin(data_), end(data_), begin(data));
|
||||
}
|
||||
|
||||
constexpr auto &operator()(const std::uint8_t x, const std::uint8_t y) noexcept {
|
||||
return data[y * Width + x];
|
||||
}
|
||||
|
||||
constexpr const auto &operator()(const std::uint8_t x, const std::uint8_t y) const noexcept {
|
||||
return data[y * Width + x];
|
||||
}
|
||||
};
|
||||
|
||||
static void putc(uint8_t x, uint8_t y, uint8_t c) {
|
||||
const auto start = 0x400 + (y * 40 + x);
|
||||
poke(start, c);
|
||||
}
|
||||
|
||||
static void put_hex(uint8_t x, uint8_t y, uint8_t value) {
|
||||
const auto put_nibble = [](auto x, auto y, uint8_t nibble) {
|
||||
if (nibble <= 9) {
|
||||
putc(x, y, nibble + 48);
|
||||
} else {
|
||||
putc(x, y, nibble - 9);
|
||||
}
|
||||
};
|
||||
|
||||
put_nibble(x + 1, y, 0xF & value);
|
||||
put_nibble(x, y, 0xF & (value >> 4));
|
||||
}
|
||||
|
||||
static void put_hex(uint8_t x, uint8_t y, uint16_t value) {
|
||||
put_hex(x+2,y, static_cast<std::uint8_t>(0xFF & value));
|
||||
put_hex(x,y, static_cast<std::uint8_t>(0xFF & (value >> 8)));
|
||||
}
|
||||
|
||||
static void put_graphic(uint8_t x, uint8_t y, const auto &graphic)
|
||||
{
|
||||
for (uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) {
|
||||
for (uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) {
|
||||
putc(cur_x + x, cur_y + y, graphic(cur_x, cur_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cls() {
|
||||
for (std::uint16_t i = 0x400; i < 0x400 + 1000; ++i) {
|
||||
poke(i, 32);
|
||||
}
|
||||
}
|
||||
|
||||
struct Clock {
|
||||
using milliseconds = std::chrono::duration<std::uint16_t, std::milli>;
|
||||
|
||||
// return elapsed time since last restart
|
||||
[[nodiscard]] milliseconds restart() {
|
||||
// stop Timer A
|
||||
poke(0xDC0E, 0b00000000);
|
||||
|
||||
// last value
|
||||
const auto previous_value = static_cast<std::uint16_t>(
|
||||
peek(0xDC04) | (static_cast<uint16_t>(peek(0xDC05)) << 8));
|
||||
|
||||
// reset timer
|
||||
poke(0xDC04, 0xFF);
|
||||
poke(0xDC05, 0xFF);
|
||||
|
||||
// restart timer A
|
||||
poke(0xDC0E, 0b00010001);
|
||||
|
||||
return milliseconds{0xFFFF - previous_value};
|
||||
}
|
||||
|
||||
Clock() { [[maybe_unused]] const auto value = restart(); }
|
||||
};
|
||||
|
||||
int main() {
|
||||
cls();
|
||||
|
||||
auto fib = [f0 = 0u, f1 = 1u] mutable {
|
||||
f0 = std::exchange(f1, f0 + f1);
|
||||
return f0;
|
||||
};
|
||||
|
||||
for (std::uint8_t y = 0; y < 25; ++y) {
|
||||
put_hex(30, y, fib());
|
||||
}
|
||||
}
|
235
examples/test_mod.cpp
Normal file
235
examples/test_mod.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
|
||||
enum Colors : uint8_t { WHITE = 0x01 };
|
||||
|
||||
static volatile uint8_t &memory_loc(const uint16_t loc) {
|
||||
return *reinterpret_cast<volatile uint8_t *>(loc);
|
||||
}
|
||||
|
||||
static void poke(const uint16_t loc, const uint8_t value) {
|
||||
memory_loc(loc) = value;
|
||||
}
|
||||
|
||||
static std::uint8_t peek(const std::uint16_t loc) { return memory_loc(loc); }
|
||||
|
||||
static void decrement_border_color() { --memory_loc(0xd020); }
|
||||
|
||||
static void increment_border_color() { ++memory_loc(0xd020); }
|
||||
|
||||
static bool joystick_down() {
|
||||
uint8_t joystick_state = peek(0xDC00);
|
||||
return (joystick_state & 2) == 0;
|
||||
}
|
||||
|
||||
unsigned int __attribute__ ((noinline)) multiply(unsigned int x, unsigned int y) {
|
||||
unsigned int result = 0;
|
||||
unsigned int input = x;
|
||||
unsigned int add_in = y;
|
||||
while (input != 0) {
|
||||
if (input & 1) {
|
||||
result += add_in;
|
||||
}
|
||||
add_in <<= 1;
|
||||
input >>= 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void use_data(std::array<char, 1024> &data);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
template<std::uint8_t Width, std::uint8_t Height>
|
||||
struct Graphic
|
||||
{
|
||||
std::array<std::uint8_t, Width * Height> data;
|
||||
|
||||
static constexpr auto width() noexcept {
|
||||
return Width;
|
||||
}
|
||||
|
||||
static constexpr auto height() noexcept {
|
||||
return Height;
|
||||
}
|
||||
|
||||
constexpr Graphic() = default;
|
||||
|
||||
constexpr Graphic(std::array<uint8_t, Width * Height> data_) noexcept : data(data_) {}
|
||||
constexpr Graphic(std::initializer_list<uint8_t> data_) noexcept {
|
||||
std::copy(begin(data_), end(data_), begin(data));
|
||||
}
|
||||
|
||||
constexpr auto &operator()(const std::uint8_t x, const std::uint8_t y) noexcept {
|
||||
return data[y * Width + x];
|
||||
}
|
||||
|
||||
constexpr const auto &operator()(const std::uint8_t x, const std::uint8_t y) const noexcept {
|
||||
return data[y * Width + x];
|
||||
}
|
||||
};
|
||||
|
||||
static void putc(uint8_t x, uint8_t y, uint8_t c) {
|
||||
const auto start = 0x400 + (y * 40 + x);
|
||||
poke(start, c);
|
||||
}
|
||||
|
||||
static void put_hex(uint8_t x, uint8_t y, uint8_t value) {
|
||||
const auto put_nibble = [](auto x, auto y, uint8_t nibble) {
|
||||
if (nibble <= 9) {
|
||||
putc(x, y, nibble + 48);
|
||||
} else {
|
||||
putc(x, y, nibble - 9);
|
||||
}
|
||||
};
|
||||
|
||||
put_nibble(x + 1, y, 0xF & value);
|
||||
put_nibble(x, y, 0xF & (value >> 4));
|
||||
}
|
||||
|
||||
static void put_hex(uint8_t x, uint8_t y, uint16_t value) {
|
||||
put_hex(x+2,y, static_cast<std::uint8_t>(0xFF & value));
|
||||
put_hex(x,y, static_cast<std::uint8_t>(0xFF & (value >> 8)));
|
||||
}
|
||||
|
||||
static void put_graphic(uint8_t x, uint8_t y, const auto &graphic)
|
||||
{
|
||||
for (uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) {
|
||||
for (uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) {
|
||||
putc(cur_x + x, cur_y + y, graphic(cur_x, cur_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Clock {
|
||||
using milliseconds = std::chrono::duration<std::uint16_t, std::milli>;
|
||||
|
||||
// return elapsed time since last restart
|
||||
[[nodiscard]] milliseconds restart() {
|
||||
// stop Timer A
|
||||
poke(0xDC0E, 0b00000000);
|
||||
|
||||
// last value
|
||||
const auto previous_value = static_cast<std::uint16_t>(
|
||||
peek(0xDC04) | (static_cast<uint16_t>(peek(0xDC05)) << 8));
|
||||
|
||||
// reset timer
|
||||
poke(0xDC04, 0xFF);
|
||||
poke(0xDC05, 0xFF);
|
||||
|
||||
// restart timer A
|
||||
poke(0xDC0E, 0b00010001);
|
||||
|
||||
return milliseconds{0xFFFF - previous_value};
|
||||
}
|
||||
|
||||
Clock() { [[maybe_unused]] const auto value = restart(); }
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
||||
// static constexpr std::array<std::uint8_t, 1000> data{0};
|
||||
// std::memcpy(const_cast<uint8_t*>(&memory_loc(0x400)), data.data(),
|
||||
// data.size());
|
||||
|
||||
static constexpr auto pic =
|
||||
Graphic<5,4>{
|
||||
78,119,77,32,32,
|
||||
101,32,32,80,32,
|
||||
101,79,101,103,32,
|
||||
76,101,76,122,88
|
||||
};
|
||||
|
||||
static constexpr auto map1 =
|
||||
Graphic<4, 2>{
|
||||
1,0,1,0,
|
||||
1,1,1,1
|
||||
};
|
||||
|
||||
static constexpr auto map2 =
|
||||
Graphic<6, 3>{
|
||||
1,0,1,0,0,0,
|
||||
1,1,1,1,0,1,
|
||||
0,0,0,1,0,0
|
||||
};
|
||||
|
||||
/*
|
||||
static constexpr auto map =
|
||||
Graphic<10, 2>{
|
||||
0,1,0,1,0,0,0,1,0,0,
|
||||
1,0,0,0,0,0,1,0,0,0,
|
||||
};
|
||||
*/
|
||||
// put_graphic(10,10,pic);
|
||||
|
||||
|
||||
const auto draw_map = [](const auto &map) {
|
||||
for (std::uint8_t y=0; y < map.height(); ++y) {
|
||||
for (std::uint8_t x = 0; x < map.width(); ++x) {
|
||||
if (map(x, y) == 1) {
|
||||
put_graphic(x*4, y*4, pic);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// draw_map(map1);
|
||||
|
||||
Clock game_clock{};
|
||||
|
||||
|
||||
std::uint16_t counter = 0;
|
||||
std::uint8_t y = 19;
|
||||
|
||||
while (true) {
|
||||
const auto us_elapsed = game_clock.restart().count();
|
||||
|
||||
draw_map(map2);
|
||||
|
||||
puts(5, 17, "timing history");
|
||||
puts(21, 17, "16bit counter");
|
||||
|
||||
|
||||
put_hex(5, y, us_elapsed);
|
||||
put_hex(21, y, counter);
|
||||
put_hex(26, y, static_cast<std::uint16_t>(multiply(counter, y)));
|
||||
// put_hex(31, y, counter*10);
|
||||
|
||||
|
||||
|
||||
if (y++ == 24) {
|
||||
y = 19;
|
||||
}
|
||||
|
||||
++counter;
|
||||
increment_border_color();
|
||||
}
|
||||
|
||||
/*
|
||||
const auto background_color = [](Colors col) {
|
||||
memory_loc(0xd021) = static_cast<uint8_t>(col);
|
||||
};
|
||||
|
||||
background_color(Colors::WHITE);
|
||||
|
||||
while(true) {
|
||||
if (joystick_down()) {
|
||||
increment_border_color();
|
||||
} else {
|
||||
decrement_border_color();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -2,15 +2,14 @@
|
||||
#define INC_6502_CPP_OPTIMIZER_HPP
|
||||
|
||||
#include "6502.hpp"
|
||||
#include "personality.hpp"
|
||||
#include <vector>
|
||||
|
||||
bool optimize(std::vector<mos6502> &instructions)
|
||||
bool optimize(std::vector<mos6502> &instructions, const Personality &personality)
|
||||
{
|
||||
// return false;
|
||||
// return false;
|
||||
|
||||
if (instructions.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
if (instructions.size() < 2) { return false; }
|
||||
|
||||
const auto next_instruction = [&instructions](auto i) {
|
||||
do {
|
||||
@ -23,16 +22,16 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
// remove unused flag-fix-up blocks
|
||||
// it might make sense in the future to only insert these if determined they are needed?
|
||||
for (size_t op = 10; op < instructions.size(); ++op) {
|
||||
if (instructions[op].opcode == mos6502::OpCode::lda || instructions[op].opcode == mos6502::OpCode::bcc || instructions[op].opcode == mos6502::OpCode::bcs) {
|
||||
if (instructions[op].opcode == mos6502::OpCode::lda || instructions[op].opcode == mos6502::OpCode::bcc
|
||||
|| instructions[op].opcode == mos6502::OpCode::bcs) {
|
||||
if (instructions[op - 1].text == "; END remove if next is lda, bcc, bcs"
|
||||
|| (instructions[op -2].text == "; END remove if next is lda, bcc, bcs" && instructions[op-1].type == ASMLine::Type::Directive)) {
|
||||
|| (instructions[op - 2].text == "; END remove if next is lda, bcc, bcs"
|
||||
&& instructions[op - 1].type == ASMLine::Type::Directive)) {
|
||||
for (size_t inner_op = op - 1; inner_op > 1; --inner_op) {
|
||||
instructions[inner_op] = mos6502(ASMLine::Type::Directive,
|
||||
"; removed unused flag fix-up: " + instructions[inner_op].to_string());
|
||||
instructions[inner_op] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed unused flag fix-up: " + instructions[inner_op].to_string());
|
||||
|
||||
if (instructions[inner_op].text.find("; BEGIN") != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
if (instructions[inner_op].text.find("; BEGIN") != std::string::npos) { return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,11 +40,11 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
|
||||
// look for redundant load of lda after a tax
|
||||
for (size_t op = 0; op < instructions.size() - 3; ++op) {
|
||||
if (instructions[op].opcode == mos6502::OpCode::sta
|
||||
&& instructions[op + 1].opcode == mos6502::OpCode::tax
|
||||
if (instructions[op].opcode == mos6502::OpCode::sta && instructions[op + 1].opcode == mos6502::OpCode::tax
|
||||
&& instructions[op + 2].opcode == mos6502::OpCode::lda
|
||||
&& instructions[op].op.value == instructions[op + 2].op.value) {
|
||||
instructions[op + 2] = mos6502(ASMLine::Type::Directive, "; removed redundant lda: " + instructions[op + 2].to_string());
|
||||
instructions[op + 2] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed redundant lda: " + instructions[op + 2].to_string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -53,41 +52,65 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
// look for redundant stores to 0-page registers with sta
|
||||
for (size_t op = 0; op < instructions.size(); ++op) {
|
||||
// todo, make sure this is in the register map
|
||||
if (instructions[op].opcode == mos6502::OpCode::sta
|
||||
&& instructions[op].op.value.size() == 3) {
|
||||
if (instructions[op].opcode == mos6502::OpCode::sta && instructions[op].op.value.size() == 3) {
|
||||
for (size_t next_op = op + 1; next_op < instructions.size(); ++next_op) {
|
||||
if (instructions[next_op].opcode != mos6502::OpCode::sta && instructions[next_op].op.value == instructions[op].op.value) {
|
||||
if (instructions[next_op].opcode != mos6502::OpCode::sta
|
||||
&& instructions[next_op].op.value == instructions[op].op.value) {
|
||||
// we just found a use of ourselves back, abort the search, there's probably something else going on
|
||||
break;
|
||||
}
|
||||
if (instructions[next_op].opcode == mos6502::OpCode::lda && instructions[next_op].op.value != instructions[op].op.value) {
|
||||
if (instructions[next_op].opcode == mos6502::OpCode::lda
|
||||
&& instructions[next_op].op.value != instructions[op].op.value) {
|
||||
// someone just loaded lda with a different value, so we need to abort!
|
||||
break;
|
||||
}
|
||||
|
||||
// abort at label
|
||||
if (instructions[next_op].type == ASMLine::Type::Label) {
|
||||
break;
|
||||
}
|
||||
if (instructions[next_op].type == ASMLine::Type::Label) { break; }
|
||||
|
||||
if (instructions[next_op].opcode == mos6502::OpCode::sta
|
||||
&& instructions[next_op].op.value == instructions[op].op.value) {
|
||||
// looks like we found a redundant store, remove the first one
|
||||
instructions[op] = mos6502(ASMLine::Type::Directive,
|
||||
"; removed redundant sta: " + instructions[op].to_string());
|
||||
instructions[op] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed redundant sta: " + instructions[op].to_string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t op = 0; op < instructions.size() - 1; ++op) {
|
||||
// look for a transfer of A -> X immediately followed by LDX
|
||||
if (instructions[op].opcode == mos6502::OpCode::sta) {
|
||||
const auto next_op = next_instruction(op);
|
||||
if (instructions[next_op].opcode == mos6502::OpCode::ldx && instructions[op].op == instructions[next_op].op) {
|
||||
auto last_comment = instructions[next_op].comment;
|
||||
instructions[next_op] = mos6502(mos6502::OpCode::tax);
|
||||
instructions[next_op].comment = last_comment;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t op = 0; op < instructions.size() - 1; ++op) {
|
||||
// look for a transfer of A -> X immediately followed by LDX
|
||||
if (instructions[op].opcode == mos6502::OpCode::tax) {
|
||||
const auto next_op = next_instruction(op);
|
||||
if (instructions[next_op].opcode == mos6502::OpCode::ldx) {
|
||||
instructions[op] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed redundant tax: " + instructions[op].to_string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t op = 0; op < instructions.size() - 1; ++op) {
|
||||
// look for a transfer of Y -> A immediately followed by A -> Y
|
||||
if (instructions[op].opcode == mos6502::OpCode::tya) {
|
||||
next_instruction(op);
|
||||
if (instructions[op].opcode == mos6502::OpCode::tay) {
|
||||
instructions[op] = mos6502(ASMLine::Type::Directive,
|
||||
"; removed redundant tay: " + instructions[op].to_string());
|
||||
const auto next_op = next_instruction(op);
|
||||
if (instructions[next_op].opcode == mos6502::OpCode::tay) {
|
||||
instructions[op] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed redundant tay: " + instructions[op].to_string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -96,50 +119,60 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
for (size_t op = 0; op < instructions.size() - 1; ++op) {
|
||||
// look for a store A -> loc immediately followed by loc -> A
|
||||
if (instructions[op].opcode == mos6502::OpCode::sta) {
|
||||
|
||||
const auto next = next_instruction(op);
|
||||
if (instructions[next].opcode == mos6502::OpCode::lda
|
||||
&& instructions[next].op == instructions[op].op) {
|
||||
instructions[next] = mos6502(ASMLine::Type::Directive,
|
||||
"; removed redundant lda: " + instructions[next].to_string());
|
||||
if (instructions[next].opcode == mos6502::OpCode::lda && instructions[next].op == instructions[op].op) {
|
||||
instructions[next] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed redundant lda: " + instructions[next].to_string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: fix this ldy redundant move, right now it doesn't
|
||||
// take into account if Y has been used
|
||||
for (auto &op : instructions) {
|
||||
if (op.type == ASMLine::Type::Instruction && op.op.type == Operand::Type::literal
|
||||
&& op.op.value == personality.get_register(1).value && op.opcode != mos6502::OpCode::sta) {
|
||||
// replace use of zero reg with literal 0
|
||||
op.op.value = "#0";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
for (size_t op = 0; op < instructions.size() - 1; ++op) {
|
||||
if (instructions[op].opcode == mos6502::OpCode::ldy && instructions[op].op.type == Operand::Type::literal) {
|
||||
auto op2 = op + 1;
|
||||
|
||||
while (op2 < instructions.size() && (instructions[op2].type != ASMLine::Type::Label)) {
|
||||
// while inside this label
|
||||
if (instructions[op2].opcode == mos6502::OpCode::ldy && instructions[op2].op.value == instructions[op].op.value) {
|
||||
instructions[op2] = mos6502(ASMLine::Type::Directive, "; removed redundant ldy: " + instructions[op2].to_string());
|
||||
return true;
|
||||
if (instructions[op2].opcode == mos6502::OpCode::ldy) {
|
||||
|
||||
if (instructions[op2].op.value == instructions[op].op.value) {
|
||||
instructions[op2] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed redundant ldy: " + instructions[op2].to_string());
|
||||
return true;
|
||||
} else {
|
||||
// if we ldy with any other value in this block then abort
|
||||
break;
|
||||
}
|
||||
}
|
||||
++op2;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
for (size_t op = 0; op < instructions.size() - 1; ++op) {
|
||||
if (instructions[op].opcode == mos6502::OpCode::lda
|
||||
&& instructions[op].op.type == Operand::Type::literal) {
|
||||
if (instructions[op].opcode == mos6502::OpCode::lda && instructions[op].op.type == Operand::Type::literal) {
|
||||
const auto operand = instructions[op].op;
|
||||
auto op2 = op + 1;
|
||||
auto op2 = op + 1;
|
||||
// look for multiple stores of the same value
|
||||
while (op2 < instructions.size() && (instructions[op2].opcode == mos6502::OpCode::sta || instructions[op2].type == ASMLine::Type::Directive)) {
|
||||
while (
|
||||
op2 < instructions.size()
|
||||
&& (instructions[op2].opcode == mos6502::OpCode::sta || instructions[op2].type == ASMLine::Type::Directive)) {
|
||||
++op2;
|
||||
}
|
||||
if (instructions[op2].opcode == mos6502::OpCode::lda
|
||||
&& operand == instructions[op2].op) {
|
||||
instructions[op2] = mos6502(ASMLine::Type::Directive,
|
||||
"; removed redundant lda: " + instructions[op2].to_string());
|
||||
if (instructions[op2].opcode == mos6502::OpCode::lda && operand == instructions[op2].op) {
|
||||
instructions[op2] =
|
||||
mos6502(ASMLine::Type::Directive, "; removed redundant lda: " + instructions[op2].to_string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -148,4 +181,4 @@ bool optimize(std::vector<mos6502> &instructions)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif//INC_6502_CPP_OPTIMIZER_HPP
|
||||
#endif// INC_6502_CPP_OPTIMIZER_HPP
|
||||
|
@ -15,94 +15,47 @@ struct C64 : Personality
|
||||
new_instructions.emplace_back(ASMLine::Type::Directive, "* = " + std::to_string(start_address));
|
||||
new_instructions.emplace_back(ASMLine::Type::Directive, "; jmp to start of program with BASIC");
|
||||
new_instructions.emplace_back(ASMLine::Type::Directive, ".byt $0B,$08,$0A,$00,$9E,$32,$30,$36,$31,$00,$00,$00");
|
||||
|
||||
// load start of stack space into stack address pointers
|
||||
new_instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$FF"));
|
||||
new_instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, std::string{stack_low_address()}));
|
||||
new_instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$CF"));
|
||||
new_instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, std::string{ stack_high_address() }));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view stack_low_address() const override
|
||||
{
|
||||
return "$02";
|
||||
}
|
||||
[[nodiscard]] std::string_view stack_high_address() const override
|
||||
{
|
||||
return "$03";
|
||||
}
|
||||
|
||||
[[nodiscard]] Operand get_register(const int reg_num) const override
|
||||
{
|
||||
switch (reg_num) {
|
||||
// http://sta.c64.org/cbm64mem.html
|
||||
case 0:
|
||||
return Operand(Operand::Type::literal, "$a7");// bit buffer for rs232
|
||||
case 1:
|
||||
return Operand(Operand::Type::literal, "$a8");// counter for rs232
|
||||
case 2:
|
||||
return Operand(Operand::Type::literal, "$05");// unused, int->fp routine pointer
|
||||
case 3:
|
||||
return Operand(Operand::Type::literal, "$06");
|
||||
case 4:
|
||||
return Operand(Operand::Type::literal, "$fb");// unused
|
||||
case 5:
|
||||
return Operand(Operand::Type::literal, "$fc");// unused
|
||||
case 6:
|
||||
return Operand(Operand::Type::literal, "$fd");// unused
|
||||
case 7:
|
||||
return Operand(Operand::Type::literal, "$fe");// unused
|
||||
case 8:
|
||||
return Operand(Operand::Type::literal, "$22");// unused
|
||||
case 9:
|
||||
return Operand(Operand::Type::literal, "$23");// unused
|
||||
case 10:
|
||||
return Operand(Operand::Type::literal, "$39");// Current BASIC line number
|
||||
case 11:
|
||||
return Operand(Operand::Type::literal, "$3a");// Current BASIC line number
|
||||
case 12:
|
||||
return Operand(Operand::Type::literal, "$61");// arithmetic register #1
|
||||
case 13:
|
||||
return Operand(Operand::Type::literal, "$62");
|
||||
case 14:
|
||||
return Operand(Operand::Type::literal, "$63");
|
||||
case 15:
|
||||
return Operand(Operand::Type::literal, "$64");
|
||||
case 16:
|
||||
return Operand(Operand::Type::literal, "$65");
|
||||
case 17:
|
||||
return Operand(Operand::Type::literal, "$69");// arithmetic register #2
|
||||
case 18:
|
||||
return Operand(Operand::Type::literal, "$6a");
|
||||
case 19:
|
||||
return Operand(Operand::Type::literal, "$6b");
|
||||
case 20:
|
||||
return Operand(Operand::Type::literal, "$6c");
|
||||
case 21:
|
||||
return Operand(Operand::Type::literal, "$6d");
|
||||
case 22:
|
||||
return Operand(Operand::Type::literal, "$57");// arithmetic register #3
|
||||
case 23:
|
||||
return Operand(Operand::Type::literal, "$58");
|
||||
case 24:
|
||||
return Operand(Operand::Type::literal, "$59");
|
||||
case 25:
|
||||
return Operand(Operand::Type::literal, "$5a");
|
||||
case 26:
|
||||
return Operand(Operand::Type::literal, "$5b");
|
||||
case 27:
|
||||
return Operand(Operand::Type::literal, "$5c");// arithmetic register #4
|
||||
case 28:
|
||||
return Operand(Operand::Type::literal, "$5d");
|
||||
case 29:
|
||||
return Operand(Operand::Type::literal, "$5e");
|
||||
case 30:
|
||||
return Operand(Operand::Type::literal, "$5f");
|
||||
case 31:
|
||||
return Operand(Operand::Type::literal, "$60");
|
||||
case 0: return Operand(Operand::Type::literal, "$a7");// bit buffer for rs232
|
||||
case 1: return Operand(Operand::Type::literal, "$a8");// counter for rs232
|
||||
case 2: return Operand(Operand::Type::literal, "$05");// unused, int->fp routine pointer
|
||||
case 3: return Operand(Operand::Type::literal, "$06");
|
||||
case 4: return Operand(Operand::Type::literal, "$fb");// unused
|
||||
case 5: return Operand(Operand::Type::literal, "$fc");// unused
|
||||
case 6: return Operand(Operand::Type::literal, "$fd");// unused
|
||||
case 7: return Operand(Operand::Type::literal, "$fe");// unused
|
||||
case 8: return Operand(Operand::Type::literal, "$22");// unused
|
||||
case 9: return Operand(Operand::Type::literal, "$23");// unused
|
||||
case 10: return Operand(Operand::Type::literal, "$39");// Current BASIC line number
|
||||
case 11: return Operand(Operand::Type::literal, "$3a");// Current BASIC line number
|
||||
case 12: return Operand(Operand::Type::literal, "$61");// arithmetic register #1
|
||||
case 13: return Operand(Operand::Type::literal, "$62");
|
||||
case 14: return Operand(Operand::Type::literal, "$63");
|
||||
case 15: return Operand(Operand::Type::literal, "$64");
|
||||
case 16: return Operand(Operand::Type::literal, "$65");
|
||||
case 17: return Operand(Operand::Type::literal, "$69");// arithmetic register #2
|
||||
case 18: return Operand(Operand::Type::literal, "$6a");
|
||||
case 19: return Operand(Operand::Type::literal, "$6b");
|
||||
case 20: return Operand(Operand::Type::literal, "$6c");
|
||||
case 21: return Operand(Operand::Type::literal, "$6d");
|
||||
case 22: return Operand(Operand::Type::literal, "$57");// arithmetic register #3
|
||||
case 23: return Operand(Operand::Type::literal, "$58");
|
||||
case 24: return Operand(Operand::Type::literal, "$59");
|
||||
case 25: return Operand(Operand::Type::literal, "$5a");
|
||||
case 26: return Operand(Operand::Type::literal, "$5b");
|
||||
case 27: return Operand(Operand::Type::literal, "$5c");// arithmetic register #4
|
||||
case 28: return Operand(Operand::Type::literal, "$5d");
|
||||
case 29: return Operand(Operand::Type::literal, "$5e");
|
||||
case 30: return Operand(Operand::Type::literal, "$5f");
|
||||
case 31: return Operand(Operand::Type::literal, "$60");
|
||||
}
|
||||
throw std::runtime_error("Unhandled register number: " + std::to_string(reg_num));
|
||||
}
|
||||
};
|
||||
|
||||
#endif//INC_6502_C_C64_HPP
|
||||
#endif// INC_6502_C_C64_HPP
|
||||
|
@ -9,8 +9,6 @@ class Personality
|
||||
public:
|
||||
virtual void insert_autostart_sequence(std::vector<mos6502> &new_instructions) const = 0;
|
||||
[[nodiscard]] virtual Operand get_register(const int reg_num) const = 0;
|
||||
[[nodiscard]] virtual std::string_view stack_low_address() const = 0;
|
||||
[[nodiscard]] virtual std::string_view stack_high_address() const= 0;
|
||||
|
||||
virtual ~Personality() = default;
|
||||
Personality(const Personality &) = delete;
|
||||
|
@ -677,7 +677,7 @@ void translate_instruction(const Personality &personality,
|
||||
}
|
||||
|
||||
if (o2.value == "__SP_H__") {
|
||||
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "$01"));
|
||||
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "#$01"));
|
||||
instructions.emplace_back(mos6502::OpCode::sta, personality.get_register(o1_reg_num));
|
||||
return;
|
||||
}
|
||||
@ -963,7 +963,7 @@ std::vector<mos6502> run(const Personality &personality, std::istream &input)
|
||||
}
|
||||
}
|
||||
|
||||
while (optimize(new_instructions)) {
|
||||
while (optimize(new_instructions, personality)) {
|
||||
// do it however many times it takes
|
||||
}
|
||||
|
||||
@ -973,7 +973,6 @@ std::vector<mos6502> run(const Personality &personality, std::istream &input)
|
||||
}
|
||||
|
||||
return new_instructions;
|
||||
|
||||
}
|
||||
|
||||
enum struct Target { C64 };
|
||||
@ -1041,8 +1040,7 @@ int main(const int argc, const char **argv)
|
||||
for (const auto &i : new_instructions) { mos6502_output << i.to_string() << '\n'; }
|
||||
}
|
||||
|
||||
const std::string xa_command = fmt::format(
|
||||
"xa -O PETSCREEN -M -o {outfile} {infile}",
|
||||
const std::string xa_command = fmt::format("xa -O PETSCREEN -M -o {outfile} {infile}",
|
||||
fmt::arg("infile", mos6502_output_file.generic_string()),
|
||||
fmt::arg("outfile", program_output_file.generic_string()));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user