mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-06-22 03:29:27 +00:00
2f76e901f9
Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
528 lines
12 KiB
C++
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);
|
|
}
|
|
|