mirror of
https://github.com/lefticus/6502-cpp.git
synced 2024-12-22 01:30:03 +00:00
Add support for D register, more opcodes
This commit is contained in:
parent
efcb6fa7ac
commit
f69150b386
51
examples/test3.cpp
Normal file
51
examples/test3.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class Colors : uint8_t
|
||||||
|
{
|
||||||
|
WHITE=0x01,
|
||||||
|
BLACK=0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
volatile uint8_t &memory_loc(const uint16_t loc)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<volatile uint8_t *>(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decrement_border_color()
|
||||||
|
{
|
||||||
|
--memory_loc(0xd020);
|
||||||
|
}
|
||||||
|
|
||||||
|
void increment_border_color()
|
||||||
|
{
|
||||||
|
++memory_loc(0xd020);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool joystick_down()
|
||||||
|
{
|
||||||
|
uint8_t joystick_state = memory_loc(0xDC00);
|
||||||
|
return (joystick_state & 0x2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const auto background_color = [](Colors col) {
|
||||||
|
memory_loc(0xd021) = static_cast<uint8_t>(col);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto border_color = [](Colors col) {
|
||||||
|
memory_loc(0xd020) = static_cast<uint8_t>(col);
|
||||||
|
};
|
||||||
|
|
||||||
|
background_color(Colors::WHITE);
|
||||||
|
|
||||||
|
bool joydown = joystick_down();
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
bool newjoydown = joystick_down();
|
||||||
|
if (joydown != newjoydown) {
|
||||||
|
increment_border_color();
|
||||||
|
joydown = newjoydown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
180
src/main.cpp
180
src/main.cpp
@ -56,9 +56,11 @@ struct mos6502 : ASMLine
|
|||||||
{
|
{
|
||||||
unknown,
|
unknown,
|
||||||
lda,
|
lda,
|
||||||
|
eor,
|
||||||
sta,
|
sta,
|
||||||
pha,
|
pha,
|
||||||
pla,
|
pla,
|
||||||
|
lsr,
|
||||||
AND,
|
AND,
|
||||||
cmp,
|
cmp,
|
||||||
bne,
|
bne,
|
||||||
@ -74,9 +76,11 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::bne:
|
case OpCode::bne:
|
||||||
return true;
|
return true;
|
||||||
case OpCode::lda:
|
case OpCode::lda:
|
||||||
|
case OpCode::eor:
|
||||||
case OpCode::sta:
|
case OpCode::sta:
|
||||||
case OpCode::pha:
|
case OpCode::pha:
|
||||||
case OpCode::pla:
|
case OpCode::pla:
|
||||||
|
case OpCode::lsr:
|
||||||
case OpCode::AND:
|
case OpCode::AND:
|
||||||
case OpCode::cmp:
|
case OpCode::cmp:
|
||||||
case OpCode::jmp:
|
case OpCode::jmp:
|
||||||
@ -91,9 +95,11 @@ struct mos6502 : ASMLine
|
|||||||
case OpCode::cmp:
|
case OpCode::cmp:
|
||||||
return true;
|
return true;
|
||||||
case OpCode::lda:
|
case OpCode::lda:
|
||||||
|
case OpCode::eor:
|
||||||
case OpCode::sta:
|
case OpCode::sta:
|
||||||
case OpCode::pha:
|
case OpCode::pha:
|
||||||
case OpCode::pla:
|
case OpCode::pla:
|
||||||
|
case OpCode::lsr:
|
||||||
case OpCode::AND:
|
case OpCode::AND:
|
||||||
case OpCode::jmp:
|
case OpCode::jmp:
|
||||||
case OpCode::bne:
|
case OpCode::bne:
|
||||||
@ -124,27 +130,31 @@ struct mos6502 : ASMLine
|
|||||||
{
|
{
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case OpCode::lda:
|
case OpCode::lda:
|
||||||
return "\tlda";
|
return "lda";
|
||||||
|
case OpCode::eor:
|
||||||
|
return "eor";
|
||||||
case OpCode::sta:
|
case OpCode::sta:
|
||||||
return "\tsta";
|
return "sta";
|
||||||
case OpCode::pha:
|
case OpCode::pha:
|
||||||
return "\tpha";
|
return "pha";
|
||||||
case OpCode::pla:
|
case OpCode::pla:
|
||||||
return "\tpla";
|
return "pla";
|
||||||
|
case OpCode::lsr:
|
||||||
|
return "lsr";
|
||||||
case OpCode::AND:
|
case OpCode::AND:
|
||||||
return "\tand";
|
return "and";
|
||||||
case OpCode::cmp:
|
case OpCode::cmp:
|
||||||
return "\tcmp";
|
return "cmp";
|
||||||
case OpCode::bne:
|
case OpCode::bne:
|
||||||
return "\tbne";
|
return "bne";
|
||||||
case OpCode::beq:
|
case OpCode::beq:
|
||||||
return "\tbeq";
|
return "beq";
|
||||||
case OpCode::jmp:
|
case OpCode::jmp:
|
||||||
return "\tjmp";
|
return "jmp";
|
||||||
case OpCode::adc:
|
case OpCode::adc:
|
||||||
return "\tadc";
|
return "adc";
|
||||||
case OpCode::sbc:
|
case OpCode::sbc:
|
||||||
return "\tsbc";
|
return "sbc";
|
||||||
case OpCode::unknown:
|
case OpCode::unknown:
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
@ -182,6 +192,8 @@ struct i386 : ASMLine
|
|||||||
andl,
|
andl,
|
||||||
ret,
|
ret,
|
||||||
movb,
|
movb,
|
||||||
|
cmpb,
|
||||||
|
movl,
|
||||||
jmp,
|
jmp,
|
||||||
jne,
|
jne,
|
||||||
je,
|
je,
|
||||||
@ -207,6 +219,8 @@ struct i386 : ASMLine
|
|||||||
if (o == "andl") return OpCode::andl;
|
if (o == "andl") return OpCode::andl;
|
||||||
if (o == "ret") return OpCode::ret;
|
if (o == "ret") return OpCode::ret;
|
||||||
if (o == "movb") return OpCode::movb;
|
if (o == "movb") return OpCode::movb;
|
||||||
|
if (o == "cmpb") return OpCode::cmpb;
|
||||||
|
if (o == "movl") return OpCode::movl;
|
||||||
if (o == "jmp") return OpCode::jmp;
|
if (o == "jmp") return OpCode::jmp;
|
||||||
if (o == "testb") return OpCode::testb;
|
if (o == "testb") return OpCode::testb;
|
||||||
if (o == "jne") return OpCode::jne;
|
if (o == "jne") return OpCode::jne;
|
||||||
@ -221,7 +235,7 @@ struct i386 : ASMLine
|
|||||||
static Operand parse_operand(std::string o)
|
static Operand parse_operand(std::string o)
|
||||||
{
|
{
|
||||||
if (o.empty()) {
|
if (o.empty()) {
|
||||||
throw std::runtime_error("Empty operand?!");
|
return Operand();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o[0] == '%') {
|
if (o[0] == '%') {
|
||||||
@ -229,6 +243,10 @@ struct i386 : ASMLine
|
|||||||
return Operand(Operand::Type::reg, 1);
|
return Operand(Operand::Type::reg, 1);
|
||||||
} else if (o == "%al") {
|
} else if (o == "%al") {
|
||||||
return Operand(Operand::Type::reg, 1);
|
return Operand(Operand::Type::reg, 1);
|
||||||
|
} else if (o == "%edx") {
|
||||||
|
return Operand(Operand::Type::reg, 4);
|
||||||
|
} else if (o == "%dl") {
|
||||||
|
return Operand(Operand::Type::reg, 4);
|
||||||
} else if (o == "%di") {
|
} else if (o == "%di") {
|
||||||
return Operand(Operand::Type::reg, 6);
|
return Operand(Operand::Type::reg, 6);
|
||||||
} else {
|
} else {
|
||||||
@ -239,23 +257,14 @@ struct i386 : ASMLine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i386(Type t, std::string o1)
|
i386(const int t_line_num, const std::string t_line_text, Type t, std::string opcode, std::string o1="", std::string o2="")
|
||||||
: ASMLine(t, o1), opcode(parse_opcode(t, o1))
|
: ASMLine(t, opcode), line_num(t_line_num), line_text(std::move(t_line_text)),
|
||||||
|
opcode(parse_opcode(t, opcode)), operand1(parse_operand(std::move(o1))), operand2(parse_operand(std::move(o2)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
i386(Type t, std::string opcode, std::string o1)
|
int line_num;
|
||||||
: ASMLine(t, opcode), opcode(parse_opcode(t, opcode)), operand1(parse_operand(std::move(o1)))
|
std::string line_text;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
i386(Type t, std::string opcode, std::string o1, std::string o2)
|
|
||||||
: ASMLine(t, opcode), opcode(parse_opcode(t, opcode)), operand1(parse_operand(std::move(o1))), operand2(parse_operand(std::move(o2)))
|
|
||||||
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
OpCode opcode;
|
OpCode opcode;
|
||||||
Operand operand1;
|
Operand operand1;
|
||||||
Operand operand2;
|
Operand operand2;
|
||||||
@ -273,6 +282,18 @@ void translate_instruction(std::vector<mos6502> &instructions, const i386::OpCod
|
|||||||
instructions.emplace_back(mos6502::OpCode::pla);
|
instructions.emplace_back(mos6502::OpCode::pla);
|
||||||
} else if (o1.type == Operand::Type::reg && o1.reg_num == 1 && o2.type == Operand::Type::literal) {
|
} else if (o1.type == Operand::Type::reg && o1.reg_num == 1 && o2.type == Operand::Type::literal) {
|
||||||
instructions.emplace_back(mos6502::OpCode::sta, o2);
|
instructions.emplace_back(mos6502::OpCode::sta, o2);
|
||||||
|
} else if (o1.type == Operand::Type::reg && o1.reg_num == 4 && o2.type == Operand::Type::literal) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pha); // transfer memory through A register, pushing and popping around it
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, o2);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pla); // transfer memory through A register, pushing and popping around it
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case i386::OpCode::movl:
|
||||||
|
if (o1.type == Operand::Type::reg && o1.reg_num == 1 && o2.type == Operand::Type::reg && o2.reg_num == 4) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, "$00"));
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Cannot translate instruction");
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
}
|
}
|
||||||
@ -280,6 +301,20 @@ void translate_instruction(std::vector<mos6502> &instructions, const i386::OpCod
|
|||||||
case i386::OpCode::movzbl:
|
case i386::OpCode::movzbl:
|
||||||
if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 1) {
|
if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 1) {
|
||||||
instructions.emplace_back(mos6502::OpCode::lda, o1);
|
instructions.emplace_back(mos6502::OpCode::lda, o1);
|
||||||
|
} else if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 4) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pha); // transfer memory through A register, pushing and popping around it
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, o1);
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pla);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case i386::OpCode::shrb:
|
||||||
|
if (o1.type == Operand::Type::reg && o1.reg_num == 1) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lsr, Operand(Operand::Type::literal, "a"));
|
||||||
|
} else if (o1.type == Operand::Type::reg && o1.reg_num == 4) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lsr, Operand(Operand::Type::literal, "$00"));
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Cannot translate instruction");
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
}
|
}
|
||||||
@ -301,9 +336,48 @@ void translate_instruction(std::vector<mos6502> &instructions, const i386::OpCod
|
|||||||
case i386::OpCode::jmp:
|
case i386::OpCode::jmp:
|
||||||
instructions.emplace_back(mos6502::OpCode::jmp, o1);
|
instructions.emplace_back(mos6502::OpCode::jmp, o1);
|
||||||
break;
|
break;
|
||||||
|
case i386::OpCode::xorl:
|
||||||
|
if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 1) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::eor, Operand(o1.type, "#" + o1.value));
|
||||||
|
} else if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 4) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pha); // transfer memory through A register, pushing and popping around it
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::eor, Operand(o1.type, "#" + o1.value));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pla);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case i386::OpCode::addl:
|
case i386::OpCode::addl:
|
||||||
if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 1) {
|
if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 1) {
|
||||||
instructions.emplace_back(mos6502::OpCode::adc, Operand(o1.type, "#" + o1.value));
|
instructions.emplace_back(mos6502::OpCode::adc, Operand(o1.type, "#" + o1.value));
|
||||||
|
} else if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 4) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pha); // transfer memory through A register, pushing and popping around it
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::adc, Operand(o1.type, "#" + o1.value));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pla);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case i386::OpCode::cmpb:
|
||||||
|
if (o1.type == Operand::Type::reg && o1.reg_num == 1 && o2.type == Operand::Type::reg && o2.reg_num == 4) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::cmp, Operand(Operand::Type::literal, "$00"));
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case i386::OpCode::andl:
|
||||||
|
if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 1) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::AND, Operand(o1.type, "#" + o1.value));
|
||||||
|
} else if (o1.type == Operand::Type::literal && o2.type == Operand::Type::reg && o2.reg_num == 4) {
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pha); // transfer memory through A register, pushing and popping around it
|
||||||
|
instructions.emplace_back(mos6502::OpCode::lda, Operand(o1.type, "#" + o1.value));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::AND, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::sta, Operand(Operand::Type::literal, "$00"));
|
||||||
|
instructions.emplace_back(mos6502::OpCode::pla); // transfer memory through A register, pushing and popping around it
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Cannot translate instruction");
|
throw std::runtime_error("Cannot translate instruction");
|
||||||
}
|
}
|
||||||
@ -322,8 +396,45 @@ void translate_instruction(std::vector<mos6502> &instructions, const i386::OpCod
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class LogLevel
|
||||||
|
{
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
|
||||||
|
void log(LogLevel ll, const i386 &i, const std::string &message)
|
||||||
|
{
|
||||||
|
const auto ll_to_s = [&ll](){
|
||||||
|
switch (ll)
|
||||||
|
{
|
||||||
|
case LogLevel::Warning:
|
||||||
|
return "warning";
|
||||||
|
case LogLevel::Error:
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
std::cerr << i.line_num << ": " << ll_to_s << ": " << message << ": `" << i.line_text << "`\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(LogLevel ll, const int line_no, const std::string &line, const std::string &message)
|
||||||
|
{
|
||||||
|
const auto ll_to_s = [&ll](){
|
||||||
|
switch (ll)
|
||||||
|
{
|
||||||
|
case LogLevel::Warning:
|
||||||
|
return "warning";
|
||||||
|
case LogLevel::Error:
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
std::cerr << line_no << ": " << ll_to_s << ": " << message << ": `" << line << "`\n";
|
||||||
|
}
|
||||||
|
|
||||||
void to_mos6502(const i386 &i, std::vector<mos6502> &instructions)
|
void to_mos6502(const i386 &i, std::vector<mos6502> &instructions)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
switch(i.type)
|
switch(i.type)
|
||||||
{
|
{
|
||||||
case ASMLine::Type::Label:
|
case ASMLine::Type::Label:
|
||||||
@ -335,6 +446,9 @@ void to_mos6502(const i386 &i, std::vector<mos6502> &instructions)
|
|||||||
translate_instruction(instructions, i.opcode, i.operand1, i.operand2);
|
translate_instruction(instructions, i.opcode, i.operand1, i.operand2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
log(LogLevel::Error, i, e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fix_overwritten_flags(std::vector<mos6502> &instructions)
|
bool fix_overwritten_flags(std::vector<mos6502> &instructions)
|
||||||
@ -390,23 +504,27 @@ int main()
|
|||||||
std::string line;
|
std::string line;
|
||||||
getline(std::cin, line);
|
getline(std::cin, line);
|
||||||
|
|
||||||
|
try {
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
if (std::regex_match(line, match, Label))
|
if (std::regex_match(line, match, Label))
|
||||||
{
|
{
|
||||||
instructions.emplace_back(ASMLine::Type::Label, match[1]);
|
instructions.emplace_back(lineno, line, ASMLine::Type::Label, match[1]);
|
||||||
} else if (std::regex_match(line, match, Directive)) {
|
} else if (std::regex_match(line, match, Directive)) {
|
||||||
instructions.emplace_back(ASMLine::Type::Directive, match[1]);
|
instructions.emplace_back(lineno, line, ASMLine::Type::Directive, match[1]);
|
||||||
} else if (std::regex_match(line, match, UnaryInstruction)) {
|
} else if (std::regex_match(line, match, UnaryInstruction)) {
|
||||||
instructions.emplace_back(ASMLine::Type::Instruction, match[1], match[2]);
|
instructions.emplace_back(lineno, line, ASMLine::Type::Instruction, match[1], match[2]);
|
||||||
} else if (std::regex_match(line, match, BinaryInstruction)) {
|
} else if (std::regex_match(line, match, BinaryInstruction)) {
|
||||||
instructions.emplace_back(ASMLine::Type::Instruction, match[1], match[2], match[3]);
|
instructions.emplace_back(lineno, line, ASMLine::Type::Instruction, match[1], match[2], match[3]);
|
||||||
} else if (std::regex_match(line, match, Instruction)) {
|
} else if (std::regex_match(line, match, Instruction)) {
|
||||||
instructions.emplace_back(ASMLine::Type::Instruction, match[1]);
|
instructions.emplace_back(lineno, line, ASMLine::Type::Instruction, match[1]);
|
||||||
} else if (line == "") {
|
} else if (line == "") {
|
||||||
//std::cout << "EmptyLine\n";
|
//std::cout << "EmptyLine\n";
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Unparsed Input, Line: " + std::to_string(lineno));
|
throw std::runtime_error("Unparsed Input, Line: " + std::to_string(lineno));
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
log(LogLevel::Error, lineno, line, e.what());
|
||||||
|
}
|
||||||
|
|
||||||
++lineno;
|
++lineno;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user