mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2025-08-10 07:25:18 +00:00
371 lines
8.7 KiB
C++
371 lines
8.7 KiB
C++
#include "stdafx.h"
|
|
#include "Disassembly.h"
|
|
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <functional>
|
|
|
|
using namespace std::placeholders;
|
|
|
|
EightBit::Disassembly::Disassembly(MOS6502& targetProcessor, const Symbols& targetSymbols)
|
|
: processor(targetProcessor),
|
|
symbols(targetSymbols) {
|
|
}
|
|
|
|
std::string EightBit::Disassembly::dump_Flags(uint8_t value) const {
|
|
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;
|
|
}
|
|
|
|
std::string EightBit::Disassembly::dump_ByteValue(uint8_t value) const {
|
|
std::ostringstream output;
|
|
output << std::hex << std::setw(2) << std::setfill('0') << (int)value;
|
|
return output.str();
|
|
}
|
|
|
|
std::string EightBit::Disassembly::dump_WordValue(uint16_t value) const {
|
|
std::ostringstream output;
|
|
output << std::hex << std::setw(4) << std::setfill('0') << (int)value;
|
|
return output.str();
|
|
}
|
|
|
|
std::string EightBit::Disassembly::disassemble(uint16_t current) const {
|
|
|
|
m_address = current;
|
|
|
|
std::ostringstream output;
|
|
|
|
auto memory = processor.getMemory();
|
|
|
|
auto cell = memory.peek(current);
|
|
|
|
output << dump_ByteValue(cell);
|
|
|
|
auto byte = memory.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 0b010: // PHP
|
|
output << disassemble_Implied("PHP");
|
|
break;
|
|
case 0b100: // BPL
|
|
output << disassemble_Relative("BPL", relative);
|
|
break;
|
|
case 0b110: // CLC
|
|
output << disassemble_Implied("CLC");
|
|
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 0b110: // SEC
|
|
output << disassemble_Implied("SEC");
|
|
break;
|
|
default: // BIT
|
|
output << disassemble_AM_00(bbb, "BIT");
|
|
break;
|
|
}
|
|
break;
|
|
case 0b010:
|
|
switch (bbb) {
|
|
case 0b000: // RTI
|
|
output << disassemble_Implied("RTI");
|
|
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 0b110: // CLI
|
|
output << disassemble_Implied("CLI");
|
|
break;
|
|
default:
|
|
throw std::domain_error("Illegal addressing mode");
|
|
}
|
|
break;
|
|
case 0b011:
|
|
switch (bbb) {
|
|
case 0b000: // RTS
|
|
output << disassemble_Implied("RTS");
|
|
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 0b110: // SEI
|
|
output << disassemble_Implied("SEI");
|
|
break;
|
|
default:
|
|
throw std::domain_error("Illegal addressing mode");
|
|
}
|
|
break;
|
|
case 0b100:
|
|
switch (bbb) {
|
|
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 0b110: // CLD
|
|
output << disassemble_Implied("CLD");
|
|
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 0b110: // SED
|
|
output << disassemble_Implied("SED");
|
|
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:
|
|
__assume(0);
|
|
}
|
|
break;
|
|
case 0b10:
|
|
switch (aaa) {
|
|
case 0b000: // ASL
|
|
output << disassemble_AM_10(bbb, "ASL");
|
|
break;
|
|
case 0b001: // ROL
|
|
output << disassemble_AM_10(bbb, "ROL");
|
|
break;
|
|
case 0b010: // LSR
|
|
output << disassemble_AM_10(bbb, "LSR");
|
|
break;
|
|
case 0b011: // ROR
|
|
output << disassemble_AM_10(bbb, "ROR");
|
|
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;
|
|
default: // DEC
|
|
output << disassemble_AM_10(bbb, "DEC");
|
|
break;
|
|
}
|
|
break;
|
|
case 0b111:
|
|
switch (bbb) {
|
|
case 0b010: // NOP
|
|
output << disassemble_Implied("NOP");
|
|
break;
|
|
default: // INC
|
|
output << disassemble_AM_10(bbb, "INC");
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
__assume(0);
|
|
}
|
|
break;
|
|
case 0b11:
|
|
throw std::domain_error("Illegal instruction group");
|
|
default:
|
|
__assume(0);
|
|
}
|
|
|
|
//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) const {
|
|
return processor.getMemory().peek(address);
|
|
}
|
|
|
|
////
|
|
|
|
std::string EightBit::Disassembly::dump_Byte(uint16_t address) const {
|
|
return dump_ByteValue(getByte(address));
|
|
}
|
|
|
|
std::string EightBit::Disassembly::dump_DByte(uint16_t address) const {
|
|
return dump_Byte(address) + dump_Byte(address + 1);
|
|
}
|
|
|
|
////
|
|
|
|
std::string EightBit::Disassembly::convertAddress(uint16_t address) const {
|
|
auto label = symbols.getLabels().find(address);
|
|
if (label != symbols.getLabels().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.getLabels().find(address);
|
|
if (label != symbols.getLabels().end())
|
|
return label->second;
|
|
std::ostringstream output;
|
|
output << "$" << dump_ByteValue(address);
|
|
return output.str();
|
|
}
|
|
|
|
std::string EightBit::Disassembly::convertConstant(uint16_t constant) const {
|
|
auto label = symbols.getConstants().find(constant);
|
|
if (label != symbols.getConstants().end())
|
|
return label->second;
|
|
return dump_DByte(constant);
|
|
}
|
|
|
|
std::string EightBit::Disassembly::convertConstant(uint8_t constant) const {
|
|
auto label = symbols.getConstants().find(constant);
|
|
if (label != symbols.getConstants().end())
|
|
return label->second;
|
|
return dump_ByteValue(constant);
|
|
}
|
|
|