#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