← index
ats/system/code.cpp
Source: ats/system/code.cpp
#include "code.hpp"

namespace interp {
    
    std::vector<TextLine> lines;
    std::unordered_map<std::string, int> label_table;
    std::unordered_map<int, int> label_line_table;
    std::ostringstream stream;
    const char *add_mode[] = { "Non mode", "Immediate", "Zero Page", "Zero Page X", "Zero Page Y", "ABSOLUTE", "ABSOLUTE X", "ABSOLUTE Y", "Implied", "Relative", "Indirect Indexed", "Indexed Indirect", "Accumulator", "Indirect", 0 };
    std::vector<std::pair<uint16_t, uint8_t>> modifiedMemoryAddresses;
    bool mem_write = false;
    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, ABSOLUTE, opc::ADC }, { 0x7D, ABSOLUTE_X, opc::ADC }, { 0x79, ABSOLUTE_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, ABSOLUTE, opc::AND }, { 0x3D, ABSOLUTE_X, opc::AND }, { 0x39, ABSOLUTE_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, ABSOLUTE, opc::ASL }, { 0x1E, ABSOLUTE_X, opc::ASL },
        // BCC
        { 0x90, RELATIVE, opc::BCC },
        // BCS
        { 0xB0, RELATIVE, opc::BCS },
        // BEQ
        { 0xF0, RELATIVE, opc::BEQ },
        // BIT
        { 0x24, ZEROPAGE, opc::BIT }, { 0x2C, ABSOLUTE, 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::BVS },
        // 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, ABSOLUTE, opc::CMP }, { 0xDD, ABSOLUTE_X, opc::CMP }, { 0xD9, ABSOLUTE_Y, opc::CMP }, { 0xC1, INDEXED_I, opc::CMP }, { 0xD1, INDIRECT_I, opc::CMP },
        // CPX
        { 0xE0, IMMEDIATE, opc::CPX }, { 0xE4, ZEROPAGE, opc::CPX }, { 0xEC, ABSOLUTE, opc::CPX },
        // CPY
        { 0xC0, IMMEDIATE, opc::CPY }, { 0xC4, ZEROPAGE, opc::CPY }, { 0xCC, ABSOLUTE, opc::CPY },
        // DEC
        { 0xC6, ZEROPAGE, opc::DEC }, { 0xD6, ZEROPAGE_X, opc::DEC }, { 0xCE, ABSOLUTE, opc::DEC }, { 0xDE, ABSOLUTE_X, opc::DEC },
        // DEX
        { 0xCA, IMPLIED, opc::DEX },
        // DEY
        { 0x88, IMPLIED, opc::DEY },
        // END
        { 0x02, IMPLIED, opc::END },
        // EOR
        { 0x49, IMMEDIATE, opc::EOR }, { 0x45, ZEROPAGE, opc::EOR }, { 0x55, ZEROPAGE_X, opc::EOR }, { 0x4D, ABSOLUTE, opc::EOR }, { 0x5D, ABSOLUTE_X, opc::EOR }, { 0x59, ABSOLUTE_Y, opc::EOR }, { 0x41, INDEXED_I, opc::EOR }, { 0x51, INDIRECT_I, opc::EOR },
        // INC
        { 0xE6, ZEROPAGE, opc::INC }, { 0xF6, ZEROPAGE_X, opc::INC }, { 0xEE, ABSOLUTE, opc::INC }, { 0xFE, ABSOLUTE_X, opc::INC },
        // INX
        { 0xE8, IMPLIED, opc::INX },
        // INY
        { 0xC8, IMPLIED, opc::INY },
        // JMP
        { 0x4C, ABSOLUTE, opc::JMP }, { 0x6C, INDIRECT, opc::JMP },
        // JSR
        { 0x20, ABSOLUTE, opc::JSR },
        // LDA
        { 0xA9, IMMEDIATE, opc::LDA }, { 0xA5, ZEROPAGE, opc::LDA }, { 0xB5, ZEROPAGE_X, opc::LDA }, { 0xAD, ABSOLUTE, opc::LDA }, { 0xBD, ABSOLUTE_X, opc::LDA }, { 0xB9, ABSOLUTE_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, ABSOLUTE, opc::LDX }, { 0xBE, ABSOLUTE_Y, opc::LDX },
        // LDY
        { 0xA0, IMMEDIATE, opc::LDY }, { 0xA4, ZEROPAGE, opc::LDY }, { 0xB4, ZEROPAGE_X, opc::LDY }, { 0xAC, ABSOLUTE, opc::LDY }, { 0xBC, ABSOLUTE_X, opc::LDY },
        // LSR
        { 0x4A, ACCUMULATOR, opc::LSR }, { 0x46, ZEROPAGE, opc::LSR }, { 0x56, ZEROPAGE_X, opc::LSR }, { 0x4E, ABSOLUTE, opc::LSR }, { 0x5E, ABSOLUTE_X, opc::LSR },
        // NOP
        { 0xEA, IMPLIED, opc::NOP },
        // ORA
        { 0x09, IMMEDIATE, opc::ORA }, { 0x05, ZEROPAGE, opc::ORA }, { 0x15, ZEROPAGE_X, opc::ORA }, { 0x0D, ABSOLUTE, opc::ORA }, { 0x1D, ABSOLUTE_X, opc::ORA }, { 0x19, ABSOLUTE_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
        { 0x2A, ACCUMULATOR, opc::ROL }, { 0x26, ZEROPAGE, opc::ROL }, { 0x36, ZEROPAGE_X, opc::ROL }, { 0x2E, ABSOLUTE, opc::ROL }, { 0x3E, ABSOLUTE_X, opc::ROL },
        // ROR
        { 0x6A, ACCUMULATOR, opc::ROR }, { 0x66, ZEROPAGE, opc::ROR }, { 0x76, ZEROPAGE_X, opc::ROR }, { 0x6E, ABSOLUTE, opc::ROR }, { 0x7E, ABSOLUTE_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, ABSOLUTE, opc::SBC }, { 0xFD, ABSOLUTE_X, opc::SBC }, { 0xF9, ABSOLUTE_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, ABSOLUTE, opc::STA }, { 0x9D, ABSOLUTE_X, opc::STA }, { 0x99, ABSOLUTE_Y, opc::STA }, { 0x81, INDEXED_I, opc::STA }, { 0x91, INDIRECT_I, opc::STA },
        // STX
        { 0x86, ZEROPAGE, opc::STX }, { 0x96, ZEROPAGE_Y, opc::STX }, { 0x8E, ABSOLUTE, opc::STX },
        // STY
        { 0x84, ZEROPAGE, opc::STY }, { 0x94, ZEROPAGE_X, opc::STY }, { 0x8C, ABSOLUTE, 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) {
                std::cout << icode::op_array[i] << " correct.\n";
            } else {
                std::cout << icode::op_array[i] << " incorrect.\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();
                if(run == true) {
                    ++proc.ip;
                }
                if(proc.ip >= instruct.size()) {
                    run = false;
                    proc.ip = 0;
                    std::cout << "Program end reached without END, use END to terminate your program.\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) {
            std::cerr << "You must run your program first with execute.\n";
            return;
        }
        run = true;
        execute();
    }
    
    void Code::step() {
        if(instruct.size()==0) return;
        if(proc.ip >= 0 && proc.ip < instruct.size()) {
            run = true;  
            procInstruct(instruct[proc.ip]);
            if(run == true) {  
                ++proc.ip;
            }
        } else {
            std::cout << "Program finished executing..";
            run = false;
            proc.ip = 0;
        }
    }
    
    void Code::printCurrent() {
        if(instruct.size()==0) return;
        if(proc.ip >= 0 && proc.ip < instruct.size())
        	std::cout << 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();
        reset_memory();
        
        if(!in_stack.empty())
        	in_stack.erase(in_stack.begin(), in_stack.end());

        if(!interp::modifiedMemoryAddresses.empty()) {
            interp::modifiedMemoryAddresses.clear();
        }
    }
    
    void Code::reset_memory() {
        memset(mem, 0, sizeof(mem));
    }

    void Code::print() {
        std::cout << "{ ";
        proc.printRegisters();
        proc.printFlags();
        std::cout << "}\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 addr) const {
        return addr < sizeof(mem) ? mem[addr] : 0;
    }
    
    void Code::poke(uint16_t address, uint8_t value) {
        if(address < sizeof(mem)) {
            mem[address] = value;
            if(mem_write == true)
                trackMemoryWrite(address, value);
        } else {
            throw std::out_of_range("Memory address out of range");
        }
    }
    
    void Code::loadFromString(const std::string& code_text) {
        reset(); // Clear existing code
        
        // Call the correct function
        if(!interp::loadCodeFromString(code_text)) {
            throw std::runtime_error("Failed to parse assembly code");
        }
    }

}