1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-17 10:06:21 +00:00

Starts to provide just a touch of reflection.

This commit is contained in:
Thomas Harte 2021-01-26 19:22:00 -05:00
parent 413e42e1b6
commit cc90935abd

View File

@ -10,6 +10,9 @@
#define InstructionSets_M50740_Instruction_h #define InstructionSets_M50740_Instruction_h
#include <cstdint> #include <cstdint>
#include <iomanip>
#include <string>
#include <sstream>
#include "../AccessType.hpp" #include "../AccessType.hpp"
namespace InstructionSet { namespace InstructionSet {
@ -106,6 +109,98 @@ constexpr bool uses_index_mode(Operation operation) {
operation == Operation::SBC; operation == Operation::SBC;
} }
/*!
@returns The name of @c operation.
*/
inline constexpr const char *operation_name(Operation operation) {
#define MAP(x) case Operation::x: return #x;
switch(operation) {
default: break;
MAP(BBC0); MAP(BBC1); MAP(BBC2); MAP(BBC3); MAP(BBC4); MAP(BBC5); MAP(BBC6); MAP(BBC7);
MAP(BBS0); MAP(BBS1); MAP(BBS2); MAP(BBS3); MAP(BBS4); MAP(BBS5); MAP(BBS6); MAP(BBS7);
MAP(BCC); MAP(BCS); MAP(BEQ); MAP(BMI); MAP(BNE); MAP(BPL); MAP(BVC); MAP(BVS);
MAP(BRA); MAP(BRK); MAP(JMP); MAP(JSR); MAP(RTI); MAP(RTS); MAP(CLC); MAP(CLD);
MAP(CLI); MAP(CLT); MAP(CLV); MAP(SEC); MAP(SED); MAP(SEI); MAP(SET); MAP(INX);
MAP(INY); MAP(DEX); MAP(DEY); MAP(FST); MAP(SLW); MAP(NOP); MAP(PHA); MAP(PHP);
MAP(PLA); MAP(PLP); MAP(STP); MAP(TAX); MAP(TAY); MAP(TSX); MAP(TXA); MAP(TXS);
MAP(TYA); MAP(ADC); MAP(SBC); MAP(AND); MAP(ORA); MAP(EOR); MAP(BIT); MAP(CMP);
MAP(CPX); MAP(CPY); MAP(LDA); MAP(LDX); MAP(LDY); MAP(TST); MAP(ASL); MAP(LSR);
MAP(CLB0); MAP(CLB1); MAP(CLB2); MAP(CLB3); MAP(CLB4); MAP(CLB5); MAP(CLB6); MAP(CLB7);
MAP(SEB0); MAP(SEB1); MAP(SEB2); MAP(SEB3); MAP(SEB4); MAP(SEB5); MAP(SEB6); MAP(SEB7);
MAP(COM); MAP(DEC); MAP(INC); MAP(ROL); MAP(ROR); MAP(RRF); MAP(LDM); MAP(STA);
MAP(STX); MAP(STY);
}
#undef MAP
return "???";
}
/*!
@returns The name of @c addressing_mode.
*/
inline constexpr const char *addressing_mode_name(AddressingMode addressing_mode) {
switch(addressing_mode) {
default: break;
case AddressingMode::Implied: return "";
case AddressingMode::Accumulator: return "A";
case AddressingMode::Immediate: return "#";
case AddressingMode::Absolute: return "abs";
case AddressingMode::AbsoluteX: return "abs, x";
case AddressingMode::AbsoluteY: return "abs, y";
case AddressingMode::ZeroPage: return "zp";
case AddressingMode::ZeroPageX: return "zp, x";
case AddressingMode::ZeroPageY: return "zp, y";
case AddressingMode::XIndirect: return "((zp, x))";
case AddressingMode::IndirectY: return "((zp), y)";
case AddressingMode::Relative: return "rel";
case AddressingMode::AbsoluteIndirect: return "(abs)";
case AddressingMode::ZeroPageIndirect: return "(zp)";
case AddressingMode::SpecialPage: return "\\sp";
case AddressingMode::ImmediateZeroPage: return "#, zp";
case AddressingMode::AccumulatorRelative: return "A, rel";
case AddressingMode::ZeroPageRelative: return "zp, rel";
}
return "???";
}
/*!
@returns The way that the address for an operation with @c addressing_mode and encoded starting from @c operation
would appear in an assembler. E.g. '$5a' for that zero page address, or '$5a, x' for zero-page indexed from $5a. This function
may access up to three bytes from @c operation onwards.
*/
inline std::string address(AddressingMode addressing_mode, const uint8_t *operation) {
std::stringstream output;
output << std::hex << std::setfill('0') << std::setw(2);
switch(addressing_mode) {
default: return "???";
case AddressingMode::Implied: return "";
case AddressingMode::Accumulator: return "A";
case AddressingMode::Immediate: output << "#$" << int(operation[1]); break;
case AddressingMode::Absolute: output << "$" << int(operation[2]) << int(operation[1]); break;
case AddressingMode::AbsoluteX: output << "$" << int(operation[2]) << int(operation[1]) << ", x"; break;
case AddressingMode::AbsoluteY: output << "$" << int(operation[2]) << int(operation[1]) << ", y"; break;
case AddressingMode::ZeroPage: output << "$" << int(operation[1]); break;
case AddressingMode::ZeroPageX: output << "$" << int(operation[1]) << ", x"; break;
case AddressingMode::ZeroPageY: output << "$" << int(operation[1]) << ", y"; break;
case AddressingMode::XIndirect: output << "(($" << int(operation[1]) << ", x))"; break;
case AddressingMode::IndirectY: output << "(($" << int(operation[1]) << "), y)"; break;
case AddressingMode::Relative: output << "+#$" << int(int8_t(operation[1])); break;
case AddressingMode::AbsoluteIndirect: output << "($" << int(operation[2]) << int(operation[1]) << ")"; break;
case AddressingMode::ZeroPageIndirect: output << "($" << int(operation[1]) << ")"; break;
case AddressingMode::SpecialPage: output << "$1f" << int(operation[1]); break;
case AddressingMode::ImmediateZeroPage: output << "#$" << int(operation[1]) << ", $" << int(int8_t(operation[2])); break;
case AddressingMode::AccumulatorRelative: output << "A, +#$" << int(int8_t(operation[1])); break;
case AddressingMode::ZeroPageRelative: output << "$" << int(operation[1]) << ", +#$" << int(int8_t(operation[2])); break;
}
return output.str();
}
/*!
Models a complete M50740-style instruction, including its operation, addressing mode and opcode.
*/
struct Instruction { struct Instruction {
Operation operation = Operation::Invalid; Operation operation = Operation::Invalid;
AddressingMode addressing_mode = AddressingMode::Implied; AddressingMode addressing_mode = AddressingMode::Implied;
@ -116,6 +211,14 @@ struct Instruction {
Instruction() {} Instruction() {}
}; };
/*!
Outputs a description of @c instruction to @c stream.
*/
inline std::ostream &operator <<(std::ostream &stream, const Instruction &instruction) {
stream << operation_name(instruction.operation) << " " << addressing_mode_name(instruction.addressing_mode);
return stream;
}
} }
} }