1
0
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:
Jason Turner 2016-07-07 10:51:54 -06:00
parent efcb6fa7ac
commit f69150b386
4 changed files with 221 additions and 52 deletions

51
examples/test3.cpp Normal file
View 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;
}
}
}

View File

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