← index
ats.web/source/code.cpp
Source: ats.web/source/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;
    }
}