EightBit/M6502/src/Disassembly.cpp
Adrian Conlon 2f76e901f9 More tidying of include files for VS2019 compatibility (plus more correct!)
Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
2021-05-29 12:18:13 +01:00

528 lines
12 KiB
C++

#include "stdafx.h"
#include "../inc/Disassembly.h"
#include "../inc/mos6502.h"
#include "../inc/Symbols.h"
#include <sstream>
#include <iomanip>
#include <functional>
using namespace std::placeholders;
EightBit::Disassembly::Disassembly(Bus& bus, MOS6502& targetProcessor, const Symbols& targetSymbols)
: m_bus(bus),
processor(targetProcessor),
symbols(targetSymbols) {
}
std::string EightBit::Disassembly::dump_Flags(uint8_t value) {
std::string returned;
returned += (value & MOS6502::NF) ? "N" : "-";
returned += (value & MOS6502::VF) ? "O" : "-";
returned += (value & MOS6502::RF) ? "R" : "-";
returned += (value & MOS6502::BF) ? "B" : "-";
returned += (value & MOS6502::DF) ? "D" : "-";
returned += (value & MOS6502::IF) ? "I" : "-";
returned += (value & MOS6502::ZF) ? "Z" : "-";
returned += (value & MOS6502::CF) ? "C" : "-";
return returned;
}
void EightBit::Disassembly::dump(std::ostream& out, int value, int width) {
out << std::hex << std::uppercase << std::setw(width) << std::setfill('0') << value;
}
std::string EightBit::Disassembly::dump_ByteValue(uint8_t value) {
std::ostringstream output;
dump(output, value, 2);
return output.str();
}
std::string EightBit::Disassembly::dump_WordValue(uint16_t value) {
std::ostringstream output;
dump(output, value, 4);
return output.str();
}
std::string EightBit::Disassembly::disassemble(uint16_t current) {
m_address = current;
std::ostringstream output;
auto cell = BUS().peek(current);
output << dump_ByteValue(cell) << " ";
auto byte = BUS().peek(current + 1);
uint16_t relative = processor.PC().word + 2 + (int8_t)byte;
auto aaa = (cell & 0b11100000) >> 5;
auto bbb = (cell & 0b00011100) >> 2;
auto cc = (cell & 0b00000011);
switch (cc) {
case 0b00:
switch (aaa) {
case 0b000:
switch (bbb) {
case 0b000: // BRK
output << disassemble_Implied("BRK");
break;
case 0b001: // DOP/NOP (0x04)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b010: // PHP
output << disassemble_Implied("PHP");
break;
case 0b011: // TOP/NOP (0b00001100, 0x0c)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b100: // BPL
output << disassemble_Relative("BPL", relative);
break;
case 0b101: // DOP/NOP (0x14)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b110: // CLC
output << disassemble_Implied("CLC");
break;
case 0b111: // TOP/NOP (0b00011100, 0x1c)
output << disassemble_AM_00(bbb, "*NOP");
break;
default:
throw std::domain_error("Illegal instruction");
}
break;
case 0b001:
switch (bbb) {
case 0b000: // JSR
output << disassemble_Absolute("JSR");
break;
case 0b010: // PLP
output << disassemble_Implied("PLP");
break;
case 0b100: // BMI
output << disassemble_Relative("BMI", relative);
break;
case 0b101: // DOP/NOP (0x34)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b110: // SEC
output << disassemble_Implied("SEC");
break;
case 0b111: // TOP/NOP (0b00111100, 0x3c)
output << disassemble_AM_00(bbb, "*NOP");
break;
default: // BIT
output << disassemble_AM_00(bbb, "BIT");
break;
}
break;
case 0b010:
switch (bbb) {
case 0b000: // RTI
output << disassemble_Implied("RTI");
break;
case 0b001: // DOP/NOP (0x44)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b010: // PHA
output << disassemble_Implied("PHA");
break;
case 0b011: // JMP
output << disassemble_Absolute("JMP");
break;
case 0b100: // BVC
output << disassemble_Relative("BVC", relative);
break;
case 0b101: // DOP/NOP (0x54)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b110: // CLI
output << disassemble_Implied("CLI");
break;
case 0b111: // TOP/NOP (0b01011100, 0x5c)
output << disassemble_AM_00(bbb, "*NOP");
break;
default:
throw std::domain_error("Illegal addressing mode");
}
break;
case 0b011:
switch (bbb) {
case 0b000: // RTS
output << disassemble_Implied("RTS");
break;
case 0b001: // DOP/NOP (0x64)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b010: // PLA
output << disassemble_Implied("PLA");
break;
case 0b011: // JMP (abs)
output << disassemble_Indirect("JMP");
break;
case 0b100: // BVS
output << disassemble_Relative("BVS", relative);
break;
case 0b101: // DOP/NOP (0x74)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b110: // SEI
output << disassemble_Implied("SEI");
break;
case 0b111: // TOP/NOP (0b01111100, 0x7c)
output << disassemble_AM_00(bbb, "*NOP");
break;
default:
throw std::domain_error("Illegal addressing mode");
}
break;
case 0b100:
switch (bbb) {
case 0b000: // DOP/NOP (0x80)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b010: // DEY
output << disassemble_Implied("DEY");
break;
case 0b100: // BCC
output << disassemble_Relative("BCC", relative);
break;
case 0b110: // TYA
output << disassemble_Implied("TYA");
break;
default: // STY
output << disassemble_AM_00(bbb, "STY");
break;
}
break;
case 0b101:
switch (bbb) {
case 0b010: // TAY
output << disassemble_Implied("TAY");
break;
case 0b100: // BCS
output << disassemble_Relative("BCS", relative);
break;
case 0b110: // CLV
output << disassemble_Implied("CLV");
break;
default: // LDY
output << disassemble_AM_00(bbb, "LDY");
break;
}
break;
case 0b110:
switch (bbb) {
case 0b010: // INY
output << disassemble_Implied("INY");
break;
case 0b100: // BNE
output << disassemble_Relative("BNE", relative);
break;
case 0b101: // DOP/NOP (0xd4)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b110: // CLD
output << disassemble_Implied("CLD");
break;
case 0b111: // TOP/NOP (0b11011100, 0xdc)
output << disassemble_AM_00(bbb, "*NOP");
break;
default: // CPY
output << disassemble_AM_00(bbb, "CPY");
break;
}
break;
case 0b111:
switch (bbb) {
case 0b010: // INX
output << disassemble_Implied("INX");
break;
case 0b100: // BEQ
output << disassemble_Relative("BEQ", relative);
break;
case 0b101: // DOP/NOP (0xf4)
output << disassemble_AM_00(bbb, "*NOP");
break;
case 0b110: // SED
output << disassemble_Implied("SED");
break;
case 0b111: // TOP/NOP (0b11111100, 0xfc)
output << disassemble_AM_00(bbb, "*NOP");
break;
default: // CPX
output << disassemble_AM_00(bbb, "CPX");
break;
}
break;
}
break;
case 0b01:
switch (aaa) {
case 0b000: // ORA
output << disassemble_AM_01(bbb, "ORA");
break;
case 0b001: // AND
output << disassemble_AM_01(bbb, "AND");
break;
case 0b010: // EOR
output << disassemble_AM_01(bbb, "EOR");
break;
case 0b011: // ADC
output << disassemble_AM_01(bbb, "ADC");
break;
case 0b100: // STA
output << disassemble_AM_01(bbb, "STA");
break;
case 0b101: // LDA
output << disassemble_AM_01(bbb, "LDA");
break;
case 0b110: // CMP
output << disassemble_AM_01(bbb, "CMP");
break;
case 0b111: // SBC
output << disassemble_AM_01(bbb, "SBC");
break;
default:
UNREACHABLE;
}
break;
case 0b10:
switch (aaa) {
case 0b000: // ASL
switch (bbb) {
case 0b110: // 0x1a
output << disassemble_Implied("*NOP");
break;
default:
output << disassemble_AM_10(bbb, "ASL");
break;
}
break;
case 0b001: // ROL
switch (bbb) {
case 0b110: // 0x3a
output << disassemble_Implied("*NOP");
break;
default:
output << disassemble_AM_10(bbb, "ROL");
break;
}
break;
case 0b010: // LSR
switch (bbb) {
case 0b110: // 0x5a
output << disassemble_Implied("*NOP");
break;
default:
output << disassemble_AM_10(bbb, "LSR");
break;
}
break;
case 0b011: // ROR
switch (bbb) {
case 0b110: // 0x7a
output << disassemble_Implied("*NOP");
break;
default:
output << disassemble_AM_10(bbb, "ROR");
break;
}
break;
case 0b100:
switch (bbb) {
case 0b010: // TXA
output << disassemble_Implied("TXA");
break;
case 0b110: // TXS
output << disassemble_Implied("TXS");
break;
default: // STX
output << disassemble_AM_10_x(bbb, "STX");
break;
}
break;
case 0b101:
switch (bbb) {
case 0b010: // TAX
output << disassemble_Implied("TAX");
break;
case 0b110: // TSX
output << disassemble_Implied("TSX");
break;
default: // LDX
output << disassemble_AM_10_x(bbb, "LDX");
break;
}
break;
case 0b110:
switch (bbb) {
case 0b010: // DEX
output << disassemble_Implied("DEX");
break;
case 0b110: // 0xda
output << disassemble_Implied("*NOP");
break;
default: // DEC
output << disassemble_AM_10(bbb, "DEC");
break;
}
break;
case 0b111:
switch (bbb) {
case 0b010: // NOP
output << disassemble_Implied("NOP");
break;
case 0b110: // 0xfa
output << disassemble_Implied("*NOP");
break;
default: // INC
output << disassemble_AM_10(bbb, "INC");
break;
}
break;
default:
UNREACHABLE;
}
break;
case 0b11:
switch (aaa) {
case 0b000:
switch (bbb) {
case 0b010:
output << disassemble_Immediate("*AAC");
break;
default:
output << disassemble_AM_01(bbb, "*SLO");
break;
}
break;
case 0b001:
switch (bbb) {
case 0b010:
output << disassemble_Immediate("*AAC");
break;
default:
output << disassemble_AM_01(bbb, "*RLA");
break;
}
break;
case 0b010:
output << disassemble_AM_01(bbb, "*SRE");
break;
case 0b011:
output << disassemble_AM_01(bbb, "*RRA");
break;
case 0b100:
output << disassemble_AM_11(bbb, "*SAX");
break;
case 0b101:
output << disassemble_AM_11(bbb, "*LAX");
break;
case 0b110:
output << disassemble_AM_11_x(bbb, "*DCP");
break;
case 0b111:
switch (bbb) {
case 0b000: // *ISB
case 0b001:
case 0b011:
case 0b100:
case 0b101:
case 0b110:
case 0b111:
output << disassemble_AM_01(bbb, "*ISB");
break;
case 0b010:
output << disassemble_AM_11(bbb, "*SBC");
break;
default:
UNREACHABLE;
}
break;
default:
throw std::domain_error("Illegal instruction group");
}
break;
default:
UNREACHABLE;
}
//const auto& instruction = processor.getInstruction(content);
//auto mode = instruction.mode;
//auto mnemomic = instruction.display;
//auto operand = DumpOperand(mode, current + 1);
//auto label = symbols.getLabels().find(current);
//if (label != symbols.getLabels().end())
// output << label->second << ": ";
//output << mnemomic << " " << operand;
return output.str();
}
////
uint8_t EightBit::Disassembly::getByte(uint16_t address) {
return BUS().peek(address);
}
uint16_t EightBit::Disassembly::getWord(uint16_t address) {
return processor.peekWord(address).word;
}
////
std::string EightBit::Disassembly::dump_Byte(uint16_t address) {
return dump_ByteValue(getByte(address));
}
std::string EightBit::Disassembly::dump_DByte(uint16_t address) {
return dump_Byte(address) + " " + dump_Byte(address + 1);
}
std::string EightBit::Disassembly::dump_Word(uint16_t address) {
return dump_WordValue(getWord(address));
}
////
std::string EightBit::Disassembly::convertAddress(uint16_t address) const {
auto label = symbols.labels().find(address);
if (label != symbols.labels().end())
return label->second;
std::ostringstream output;
output << "$" << dump_WordValue(address);
return output.str();
}
std::string EightBit::Disassembly::convertAddress(uint8_t address) const {
auto label = symbols.labels().find(address);
if (label != symbols.labels().end())
return label->second;
std::ostringstream output;
output << "$" << dump_ByteValue(address);
return output.str();
}
std::string EightBit::Disassembly::convertConstant(uint16_t constant) {
auto label = symbols.constants().find(constant);
if (label != symbols.constants().end())
return label->second;
return dump_DByte(constant);
}
std::string EightBit::Disassembly::convertConstant(uint8_t constant) const {
auto label = symbols.constants().find(constant);
if (label != symbols.constants().end())
return label->second;
return dump_ByteValue(constant);
}