← index
cplusplus2x.Examples/C++20/MasterX/src/apps/ats/code.cpp
Source: cplusplus2x.Examples/C++20/MasterX/src/apps/ats/code.cpp
#include "code.hpp"

std::ostringstream stream;

namespace interp {

    std::vector<TextLine> lines;
    std::unordered_map<std::string, int> label_table;
    std::unordered_map<int, int> label_line_table;

    const char *add_mode[] = {"Non mode", "Immediate", "Zero Page", "Zero Page X", "Zero Page Y", "Absoulte", "Absoulte X", "Absoulte Y", "Implied", "Relative", "Indirect Indexed", "Indexed Indirect", "Accumulator", "Indirect", 0};

    using namespace icode;

    iCodeInstruction inst[] = {{opc::ADC, i_adc}, {opc::AND, i_and}, {opc::ASL, i_asl}, {opc::BCC, i_bcc}, {opc::BCS, i_bcs}, {opc::BEQ, i_beq}, {opc::BIT, i_bit}, {opc::BMI, i_bmi}, {opc::BNE, i_bne}, {opc::BPL, i_bpl}, {opc::BRK, i_brk}, {opc::BVC, i_bvc}, {opc::BVS, i_bvs}, {opc::CLC, i_clc}, {opc::CLD, i_cld}, {opc::CLI, i_cli}, {opc::CLV, i_clv}, {opc::CMP, i_cmp}, {opc::CPX, i_cpx}, {opc::CPY, i_cpy}, {opc::DEC, i_dec}, {opc::DEX, i_dex}, {opc::DEY, i_dey}, {opc::END, i_end}, {opc::EOR, i_eor}, {opc::INC, i_inc}, {opc::INT, i_int}, {opc::INX, i_inx}, {opc::INY, i_iny}, {opc::JMP, i_jmp}, {opc::JSR, i_jsr}, {opc::LDA, i_lda}, {opc::LDM, i_ldm}, {opc::LDX, i_ldx}, {opc::LDY, i_ldy}, {opc::LSR, i_lsr}, {opc::NOP, i_nop}, {opc::ORA, i_ora}, {opc::PHA, i_pha}, {opc::PHP, i_php}, {opc::PLA, i_pla}, {opc::PLP, i_plp}, {opc::ROL, i_rol}, {opc::ROR, i_ror}, {opc::RTI, i_rti}, {opc::RTS, i_rts}, {opc::SBC, i_sbc}, {opc::SEC, i_sec}, {opc::SED, i_sed}, {opc::SEI, i_sei}, {opc::STA, i_sta}, {opc::STX, i_stx}, {opc::STY, i_sty}, {opc::TAX, i_tax}, {opc::TAY, i_tay}, {opc::TSX, i_tsx}, {opc::TXA, i_txa}, {opc::TXS, i_txs}, {opc::TYA, i_tya}};

    at_code m_code[] = {
        // ADC
        {0x69, IMMEDIATE, opc::ADC},
        {0x65, ZEROPAGE, opc::ADC},
        {0x75, ZEROPAGE_X, opc::ADC},
        {0x6D, ABSOULTE, opc::ADC},
        {0x7D, ABSOULTE_X, opc::ADC},
        {0x79, ABSOULTE_Y, opc::ADC},
        {0x61, INDEXED_I, opc::ADC},
        {0x71, INDIRECT_I, opc::ADC},
        // AND
        {0x29, IMMEDIATE, opc::AND},
        {0x25, ZEROPAGE, opc::AND},
        {0x35, ZEROPAGE_X, opc::AND},
        {0x2D, ABSOULTE, opc::AND},
        {0x3D, ABSOULTE_X, opc::AND},
        {0x39, ABSOULTE_Y, opc::AND},
        {0x21, INDEXED_I, opc::AND},
        {0x31, INDIRECT_I, opc::AND},
        // ASL
        {0x0A, ACCUMULATOR, opc::ASL},
        {0x06, ZEROPAGE, opc::ASL},
        {0x16, ZEROPAGE_X, opc::ASL},
        {0x0E, ABSOULTE, opc::ASL},
        {0x1E, ABSOULTE_X, opc::ASL},
        // BCC
        {0x90, RELATIVE, opc::BCC},
        // BCS
        {0xB0, RELATIVE, opc::BCS},
        // BEQ
        {0xF0, RELATIVE, opc::BEQ},
        // BIT
        {0x24, ZEROPAGE, opc::BIT},
        {0x2C, ABSOULTE, opc::BIT},
        // BMI
        {0x30, RELATIVE, opc::BMI},
        // BNE
        {0xD0, RELATIVE, opc::BNE},
        // BPL
        {0x10, RELATIVE, opc::BPL},
        // BRK
        {0x00, IMPLIED, opc::BRK},
        // BVC
        {0x50, RELATIVE, opc::BVC},
        // BVS
        {0x70, RELATIVE, opc::BVC},
        // CLC
        {0x18, IMPLIED, opc::CLC},
        // CLD
        {0xD8, IMPLIED, opc::CLD},
        // CLI
        {0x58, IMPLIED, opc::CLI},
        // CLV
        {0xB8, IMPLIED, opc::CLV},
        // CMP
        {0xC9, IMMEDIATE, opc::CMP},
        {0xC5, ZEROPAGE, opc::CMP},
        {0xD5, ZEROPAGE_X, opc::CMP},
        {0xCD, ABSOULTE, opc::CMP},
        {0xDD, ABSOULTE_X, opc::CMP},
        {0xD9, ABSOULTE_Y, opc::CMP},
        {0xD9, ABSOULTE_Y, opc::CMP},
        {0xC1, INDEXED_I, opc::CMP},
        {0xD1, INDIRECT_I, opc::CMP},
        // CPX
        {0xE0, IMMEDIATE, opc::CPX},
        {0xE4, ZEROPAGE, opc::CPX},
        {0xEC, ABSOULTE, opc::CPX},
        // CPY
        {0xC0, IMMEDIATE, opc::CPY},
        {0xC4, ZEROPAGE, opc::CPY},
        {0xCC, ABSOULTE, opc::CPY},
        // DEC
        {0xC6, ZEROPAGE, opc::DEC},
        {0xD6, ZEROPAGE_X, opc::DEC},
        {0xCE, ABSOULTE, opc::DEC},
        {0xDE, ABSOULTE_X, opc::DEC},
        // DEX
        {0xCA, IMPLIED, opc::DEX},
        // DEY
        {0x88, IMPLIED, opc::DEY},
        // END
        {0x01, IMPLIED, opc::END},
        // EOR
        {0x49, IMMEDIATE, opc::EOR},
        {0x45, ZEROPAGE, opc::EOR},
        {0x55, ZEROPAGE_X, opc::EOR},
        {0x4D, ABSOULTE, opc::EOR},
        {0x5D, ABSOULTE_X, opc::EOR},
        {0x59, ABSOULTE_Y, opc::EOR},
        {0x41, INDEXED_I, opc::EOR},
        {0x51, INDIRECT_I, opc::EOR},
        // INC
        {0xE6, ZEROPAGE, opc::INC},
        {0xF6, ZEROPAGE_X, opc::INC},
        {0xEE, ABSOULTE, opc::INC},
        {0xFE, ABSOULTE_X, opc::INC},
        // INX
        {0xE8, IMPLIED, opc::INX},
        // INY
        {0xC8, IMPLIED, opc::INY},
        // JMP
        {0x4C, ABSOULTE, opc::JMP},
        {0x6C, INDIRECT, opc::JMP},
        // JSR
        {0x20, ABSOULTE, opc::JSR},
        // LDA
        {0xA9, IMMEDIATE, opc::LDA},
        {0xA5, ZEROPAGE, opc::LDA},
        {0xB5, ZEROPAGE_X, opc::LDA},
        {0xAD, ABSOULTE, opc::LDA},
        {0xBD, ABSOULTE_X, opc::LDA},
        {0xB9, ABSOULTE_Y, opc::LDA},
        {0xA1, INDEXED_I, opc::LDA},
        {0xB1, INDIRECT_I, opc::LDA},
        // LDX
        {0xA2, IMMEDIATE, opc::LDX},
        {0xA6, ZEROPAGE, opc::LDX},
        {0xB6, ZEROPAGE_Y, opc::LDX},
        {0xAE, ABSOULTE, opc::LDX},
        {0xA1, INDEXED_I, opc::LDX},
        {0xB1, INDIRECT_I, opc::LDX},
        {0xBE, ABSOULTE_Y, opc::LDX},
        // LDY
        {0xA0, IMMEDIATE, opc::LDY},
        {0xA4, ZEROPAGE, opc::LDY},
        {0xB4, ZEROPAGE_X, opc::LDY},
        {0xAC, ABSOULTE, opc::LDY},
        {0xBC, ABSOULTE_X, opc::LDY},
        // LSR
        {0x4A, ACCUMULATOR, opc::LSR},
        {0x46, ZEROPAGE, opc::LSR},
        {0x56, ZEROPAGE_X, opc::LSR},
        {0x4E, ABSOULTE, opc::LSR},
        {0x5E, ABSOULTE_X, opc::LSR},
        // NOP
        {0xEA, IMPLIED, opc::NOP},
        // ORA
        {0x09, IMMEDIATE, opc::ORA},
        {0x05, ZEROPAGE, opc::ORA},
        {0x15, ZEROPAGE_X, opc::ORA},
        {0x0D, ABSOULTE, opc::ORA},
        {0x1D, ABSOULTE_X, opc::ORA},
        {0x19, ABSOULTE_Y, opc::ORA},
        {0x01, INDEXED_I, opc::ORA},
        {0x11, INDIRECT_I, opc::ORA},
        // PHA
        {0x48, IMPLIED, opc::PHA},
        // PHP
        {0x08, IMPLIED, opc::PHP},
        // PLA
        {0x68, IMPLIED, opc::PLA},
        // PLP
        {0x28, IMPLIED, opc::PLP},
        // ROL
        {0x21, ACCUMULATOR, opc::ROL},
        {0x26, ZEROPAGE, opc::ROL},
        {0x36, ZEROPAGE_X, opc::ROL},
        {0x2E, ABSOULTE, opc::ROL},
        {0x3E, ABSOULTE_X, opc::ROL},
        // ROR
        {0x6A, ACCUMULATOR, opc::ROR},
        {0x66, ZEROPAGE, opc::ROR},
        {0x76, ZEROPAGE_X, opc::ROR},
        {0x6E, ABSOULTE, opc::ROR},
        {0x7E, ABSOULTE_X, opc::ROR},
        // RTI
        {0x40, IMPLIED, opc::RTI},
        // RTS
        {0x60, IMPLIED, opc::RTS},
        // SBC
        {0xE9, IMMEDIATE, opc::SBC},
        {0xE5, ZEROPAGE, opc::SBC},
        {0xF5, ZEROPAGE_X, opc::SBC},
        {0xED, ABSOULTE, opc::SBC},
        {0xFD, ABSOULTE_X, opc::SBC},
        {0xF9, ABSOULTE_Y, opc::SBC},
        {0xE1, INDEXED_I, opc::SBC},
        {0xF1, INDIRECT_I, opc::SBC},
        // SEC
        {0x38, IMPLIED, opc::SEC},
        // SED
        {0xF8, IMPLIED, opc::SED},
        // SEI
        {0x78, IMPLIED, opc::SEI},
        // STA
        {0x85, ZEROPAGE, opc::STA},
        {0x95, ZEROPAGE_X, opc::STA},
        {0x8D, ABSOULTE, opc::STA},
        {0x9D, ABSOULTE_X, opc::STA},
        {0x99, ABSOULTE_Y, opc::STA},
        {0x81, INDEXED_I, opc::STA},
        {0x91, INDIRECT_I, opc::STA},
        // STX
        {0x86, ZEROPAGE, opc::STX},
        {0x96, ZEROPAGE_Y, opc::STX},
        {0x8E, ABSOULTE, opc::STX},
        // STY
        {0x84, ZEROPAGE, opc::STY},
        {0x94, ZEROPAGE_X, opc::STY},
        {0x8C, ABSOULTE, opc::STY},
        // TAX
        {0xAA, IMPLIED, opc::TAX},
        // TAY
        {0xA8, IMPLIED, opc::TAY},
        // TSX
        {0xBA, IMPLIED, opc::TSX},
        // TXA
        {0x8A, IMPLIED, opc::TXA},
        // TXS
        {0x9A, IMPLIED, opc::TXS},
        // TYA
        {0x98, IMPLIED, opc::TYA},
        {0x0, 0x0, opc::NOTINC}};

    void testcodes() {
        for (unsigned int i = 0; icode::op_array[i] != 0; ++i) {
            icode::opc c = static_cast<icode::opc>(i);
            if (inst[i].opcode == c) {
                stream << icode::op_array[i] << " correct.\r\n";
            } else {
                stream << icode::op_array[i] << " incorrect.\r\n";
            }
        }
    }

    Code::Code() {
        reset_memory();
    }

    void Code::start(bool debug) {
        run = true;
        if (!in_stack.empty())
            in_stack.erase(in_stack.begin(), in_stack.end());
        proc.clrFlags();
        proc.ip = 0;
        execute(debug);
    }

    void Code::stop() {
        run = false;
    }

    void Code::end() {
        run = false;
        proc.ip = 0;
        if (!in_stack.empty())
            in_stack.erase(in_stack.begin(), in_stack.end());
        if (!stack.empty())
            stack.erase(stack.begin(), stack.end());
    }

    void Code::pause() {
        run = false;
    }

    void Code::execute(bool debug) {
        while (run == true) {
            if (proc.ip >= 0) {
                if (debug == true)
                    printCurrent();
                procInstruct(instruct[proc.ip]);
                if (run == true && debug == true)
                    print();
                ++proc.ip;
                if (proc.ip > instruct.size()) {
                    run = false;
                    proc.ip = 0;
                    stream << "Program end reached without END, use END to terminate your program.\r\n";
                    if (!in_stack.empty())
                        in_stack.erase(in_stack.begin(), in_stack.end());
                    if (!stack.empty())
                        stack.erase(stack.begin(), stack.end());
                    break;
                }
            }
        }
    }

    void Code::cont() {
        if (proc.ip == 0) {
            stream << "You must run your program first with execute.\r\n";
            return;
        }
        run = true;
        execute();
    }

    void Code::step() {
        if (instruct.size() == 0)
            return;
        if (proc.ip >= 0 && proc.ip < instruct.size()) {
            if (instruct[proc.ip].opcode == opc::END)
                procInstruct(instruct[proc.ip]);
            else {
                procInstruct(instruct[proc.ip++]);
            }
        } else {
            stream << "Program finished executing..\r\n";
            run = false;
            proc.ip = 0;
        }
    }

    void Code::printCurrent() {
        if (instruct.size() == 0)
            return;
        if (proc.ip >= 0 && proc.ip < instruct.size())
            stream << instruct[proc.ip];
    }

    void Code::reset() {
        if (!instruct.empty())
            instruct.erase(instruct.begin(), instruct.end());

        proc.clrFlags();

        if (!stack.empty())
            stack.erase(stack.begin(), stack.end());

        proc.reset();

        if (!in_stack.empty())
            in_stack.erase(in_stack.begin(), in_stack.end());
    }

    void Code::reset_memory() {
        memset(mem, 0, sizeof(mem));
    }

    void Code::print() {
        stream << "{ ";
        proc.printRegisters();
        proc.printFlags();
        stream << "}\r\n";
    }

    void Code::procInstruct(icode::Instruction &i) {
        unsigned int op_code = static_cast<unsigned int>(i.opcode);
        if (op_code < static_cast<int>(icode::opc::NOTINC))
            inst[op_code].call_back(*this);
    }

    uint8_t Code::peek(uint16_t address) const {
        return mem[address];
    }

    void Code::poke(uint16_t address, uint8_t value) {
        mem[address] = value;
    }
} // namespace interp