1
0
mirror of https://github.com/lefticus/6502-cpp.git synced 2024-07-18 05:29:03 +00:00

Fix up some optimizer passes

This commit is contained in:
Jason Turner 2021-05-13 23:35:57 -06:00
parent 28ebf888e3
commit e7a3db9dda
7 changed files with 539 additions and 137 deletions

View 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
View 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
View 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();
}
}
*/
}

View File

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

View File

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

View File

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

View File

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