#include "code.hpp" #include<cctype> #include "translate.hpp" #include "function.hpp" namespace icode { const char *op_array[] = { "adc", "and", "asl", "bcc", "bcs", "beq", "bit", "bmi","bne", "bpl", "brk", "bvc","bvs", "clc", "cld", "cli", "clv", "cmp","cpx","cpy","dec","dex", "dey", "end", "eor", "inc", "int", "inx", "iny", "jmp", "jsr","lda", "ldm","ldx", "ldy","lsr", "nop", "ora", "pha", "php", "pla", "plp", "rol", "ror","rti","rts", "sbc", "sec","sed", "sei", "sta", "stx", "sty", "tax", "tay", "tsx","txa","txs", "tya", 0 }; std::ostream &operator<<(std::ostream &out, opc c) { if(c != opc::NOTINC) out << op_array[static_cast<unsigned int>(c)]; return out; } Operand::Operand() : op(0), op_t(op_type::NULL_TYPE) {} Operand::Operand(const uint32_t &operand, const op_type &operand_type) : op(operand), op_t(operand_type) {} Operand::Operand(const Operand &o) :op(o.op), op_t(o.op_t), label_text(o.label_text), label_index(o.label_index) {} Operand &Operand::operator=(const Operand &o) { op = o.op; op_t = o.op_t; label_text = o.label_text; label_index = o.label_index; return *this; } Instruction::Instruction() : opcode(opc::NOTINC) { line_num = 0; label = false; } Instruction::Instruction(unsigned int iline, const opc &op_code, unsigned int m, const Operand &i_op1, const Operand &i_op2) : line_num(iline), opcode(op_code), mode(m), op1(i_op1), op2(i_op2) {} Instruction::Instruction(const Instruction &i) : instruction_text(i.instruction_text), op_byte(i.op_byte), line_num(i.line_num), opcode(i.opcode), op1(i.op1), op2(i.op2), mode(i.mode), label(i.label), label_text(i.label_text), label_index(i.label_index), text(i.text) { } Instruction &Instruction::operator=(const Instruction &i) { instruction_text = i.instruction_text; opcode = i.opcode; op1 = i.op1; op2 = i.op2; line_num = i.line_num; label_text = i.label_text; op_byte = i.op_byte; mode = i.mode; label = i.label; text = i.text; label_index = i.label_index; return *this; } void Instruction::set(unsigned int iline, const opc &c, unsigned int m, const Operand &o1, const Operand &o2) { opcode = c; op1 = o1; op2 = o2; mode = m; line_num = iline; } std::string instructionToHex(Instruction &i) { if(i.mode <= 0 ||i.mode > interp::INDIRECT) { return "invalid address mode"; } std::ostringstream stream; stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast<unsigned int>(i.op_byte); switch(i.op1.op_t) { case icode::op_type::OP_MEMORY: { if(i.mode != interp::ZEROPAGE && i.mode != interp::ZEROPAGE_X && i.mode != interp::ZEROPAGE_Y) stream << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << i.op1.op; else stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op; } break; case icode::op_type::OP_DECIMAL: stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op; break; case icode::op_type::OP_REGISTER_A: break; case icode::op_type::OP_REGISTER_X: break; case icode::op_type::OP_REGISTER_Y: break; case icode::op_type::OP_LABEL: stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op; break; case icode::op_type::OP_LABELTEXT: { auto it = interp::label_table.find(i.op1.label_text); if(it != interp::label_table.end()) { //out << "Branch Label: " << i.op1.label_text << " "; // calculate labe stream << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << it->second+1; } else { code.stop(); } } break; default: break; } return stream.str(); } std::string instructionToBinary(Instruction &i) { if(i.mode <= 0 || i.mode > interp::INDIRECT) { return "invalid address mode"; } std::ostringstream stream; stream << std::bitset<8>(i.op_byte); switch(i.op1.op_t) { case icode::op_type::OP_MEMORY: { if(i.mode != interp::ZEROPAGE && i.mode != interp::ZEROPAGE_X && i.mode != interp::ZEROPAGE_Y) stream << std::bitset<16>(static_cast<uint16_t>(i.op1.op)); else stream << std::bitset<8>(i.op1.op); } break; case icode::op_type::OP_DECIMAL: stream << std::bitset<8>(i.op1.op); break; case icode::op_type::OP_REGISTER_A: break; case icode::op_type::OP_REGISTER_X: break; case icode::op_type::OP_REGISTER_Y: break; case icode::op_type::OP_LABEL: stream << std::bitset<8>(i.op1.op); break; case icode::op_type::OP_LABELTEXT: stream << std::bitset<16>(interp::label_table[i.op1.label_text]); //out << "Branch Label: " << i.op1.label_text << " "; // calculate label break; default: break; } return stream.str(); } std::ostream &operator<<(std::ostream &out, Instruction &i) { std::ostringstream stream; stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast<unsigned int>(i.op_byte); if(i.mode <= 0 ||i.mode > interp::INDIRECT) { out << "address mode unknown value: " << i.mode << "..\n"; return out; } out << "Line: " << std::dec << i.line_num << " [" << i.instruction_text << "] - Address Mode: " << interp::add_mode[i.mode] << " Opcode: " << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast<unsigned int>(i.op_byte) << " "; switch(i.op1.op_t) { case icode::op_type::OP_MEMORY: if(i.mode != interp::ZEROPAGE && i.mode != interp::ZEROPAGE_X && i.mode != interp::ZEROPAGE_Y) { out << "Operand 1 [Memory Address]: " << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << i.op1.op << " "; stream << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << i.op1.op; } else { out << "Operand 1 [Zero Page Memory Address]: " << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op << " "; stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op; } break; case icode::op_type::OP_DECIMAL: out << "Operand 1 [Byte Constant]: " << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op << " "; stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op; break; case icode::op_type::OP_REGISTER_A: out << "Operand 1 [Register A]: "; // register here break; case icode::op_type::OP_REGISTER_X: out << "Operand 1 [Regsiter X]:"; break; case icode::op_type::OP_REGISTER_Y: out << "Operand 1 [Register Y]:"; break; case icode::op_type::OP_LABEL: out << "Branch value: " << std::setfill('0') << std::setw(2) << i.op1.op << " "; stream << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << i.op1.op; break; case icode::op_type::OP_LABELTEXT: { out << "Branch Label: " << i.op1.label_text << " "; auto it = interp::label_table.find(i.op1.label_text); if(it == interp::label_table.end()) { std::cerr << "Error: Could not find label.\n"; code.stop(); } else { //out << "Branch Label: " << i.op1.label_text << " "; // calculate label stream << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << it->second+1; } } break; default: break; } // output operand 2 std::cout << "\nHex for Machine code: " << stream.str() << "\n"; return out; } std::string lcase(const std::string &text) { std::string n; for(unsigned int i = 0; i < text.size(); ++i) { n += tolower(text[i]); } return n; } uint32_t toHex(const std::string &text) { std::istringstream stream(text); uint32_t val = 0; stream >> std::hex >> val; return val; } opc strtoInc(const std::string &inc) { std::string in = lcase(inc); for(unsigned int i = 0; op_array[i] != 0; ++i) { if(in == op_array[i]) return static_cast<opc>(i); } return opc::NOTINC; } Processor::Processor() { reset(); } void Processor::setFlag(proc_Flags flag, unsigned int set) { flags[flag] = set; } void Processor::setFlags(uint8_t b) { flags = b; } unsigned int Processor::getFlag(proc_Flags flag) { return (flags[flag] == 1); } void Processor::clrFlags() { for(uint8_t i = 0; i < 8; ++i) setFlag(proc_Flags(i), 0); } uint8_t Processor::valFlags() { return static_cast<uint8_t>(flags.to_ulong()); } void Processor::reset() { for(uint8_t i = 0; i < 8; ++i) { setFlag(proc_Flags(i), 0); } setFlag(proc_Flags(5), 1); reg_x = reg_y = reg_a = 0; ip = 0; sp = 0xFF; std::cout << "ats: Processor reset - SP initialized to " << (int)sp << "\n"; } void Processor::setIp(const address_size &ip_val) { ip = ip_val; } address_size Processor::getIp() const { return ip; } void Processor::printFlags() { std::cout << "C:" << getFlag(FLAG_CARRY) << " Z:" << getFlag(FLAG_ZERO) << " I:" << getFlag(FLAG_INTERRUPT) << " D:" << getFlag(FLAG_DECIMAL) << " B:" << getFlag(FLAG_BREAK) << " E:" << getFlag(FLAG_EXPANSION) << " V:" << getFlag(FLAG_OVERFLOW) << " N:" << getFlag(FLAG_NEGATIVE) << " "; } void Processor::printRegisters() { std::cout << "[ IP:" << ip << " X:" << std::hex << std::uppercase << static_cast<int>(reg_x) << " Y:" << std::hex << std::uppercase << static_cast<int>(reg_y) << " A:" << std::hex << std::uppercase << static_cast<int>(reg_a) << " P:" << std::hex << std::uppercase << static_cast<int>(valFlags()) << " ] "; } uint8_t calculateStatus(icode::Processor &proc) { uint8_t status = 0; status |= (proc.getFlag(icode::FLAG_CARRY) ? 0x01 : 0); status |= (proc.getFlag(icode::FLAG_ZERO) ? 0x02 : 0); status |= (proc.getFlag(icode::FLAG_INTERRUPT) ? 0x04 : 0); status |= (proc.getFlag(icode::FLAG_DECIMAL) ? 0x08 : 0); status |= (proc.getFlag(icode::FLAG_BREAK) ? 0x10 : 0); status |= 0x20; // Always set bit 5 (unused bit) status |= (proc.getFlag(icode::FLAG_OVERFLOW) ? 0x40 : 0); status |= (proc.getFlag(icode::FLAG_NEGATIVE) ? 0x80 : 0); return status; } void setStatus(icode::Processor &proc, uint8_t status) { proc.setFlag(icode::FLAG_CARRY, (status & 0x01) != 0); proc.setFlag(icode::FLAG_ZERO, (status & 0x02) != 0); proc.setFlag(icode::FLAG_INTERRUPT, (status & 0x04) != 0); proc.setFlag(icode::FLAG_DECIMAL, (status & 0x08) != 0); proc.setFlag(icode::FLAG_BREAK, (status & 0x10) != 0); proc.setFlag(icode::FLAG_OVERFLOW, (status & 0x40) != 0); proc.setFlag(icode::FLAG_NEGATIVE, (status & 0x80) != 0); } }