#include "CPU.h" #include #include #include #include #include #include #include #include "Exceptions.h" #include "InstructionModifierLookup.h" static const Instruction s_EmptyInstruction{}; CPU::CPU(std::shared_ptr& bus) : m_Bus(bus), m_IsHalted(false), m_Context({m_Instruction, m_InstructionPointer, m_Flags, m_Registers, m_Bus, m_IsHalted}) { m_InstructionPointer = 0x00008000; for(int i = 0; i < 8; i++) { m_Registers[i] = 0; } for(int i = 0; i < 8; i++) { m_SegmentRegisters[i] = 0; } } void CPU::Step() { FetchDecode(); Execute(); } void CPU::Dump() { std::cout << "--TRACE-- "; std::cout << std::endl; for(uint8_t i = 0; i < 8; i++) { std::cout << x86::Register2Str((x86::Register)i) << ": " << m_Registers[i] << " | "; } std::cout << std::endl; std::bitset<32> flags(m_Flags); std::cout << "IP: " << std::hex << m_InstructionPointer << " | FLAGS: " << flags; std::cout << std::endl; } void CPU::Reset() { for(uint8_t i = 0; i < 8; i++) { m_Registers[i] = 0; m_SegmentRegisters[i] = 0; } m_InstructionPointer = 0x8000; m_Flags = 0; std::cout << "[CPU] State Flushed!" << std::endl; m_IsHalted = false; m_Instruction = s_EmptyInstruction; } CPUStatus CPU::GetStatus() { return (CPUStatus){.m_Registers = m_Registers, .m_IP = m_InstructionPointer, .m_Instruction = m_Instruction}; } void CPU::FetchDecode() { m_Instruction = s_EmptyInstruction; uint8_t opcode_raw = m_Bus->AccessX(m_InstructionPointer); Opcode opcode = static_cast(opcode_raw); auto& instruction_table = GetInstructionTable(); if(instruction_table[opcode_raw].m_Executor == nullptr) { std::cout << "Encoding: " << opcode_raw << std::endl; std::string exception = "[CPU] [FetchDecode] Opcode is not in instruction table! Opcode_raw: " + std::to_string(opcode_raw); throw CPUException(exception); } auto& instruction = instruction_table[opcode_raw]; uint8_t encoding_mask = 0b00001111; uint8_t encoding = instruction.m_Encoding & encoding_mask; uint8_t immediate = instruction.m_Encoding & ~encoding_mask; m_Instruction.m_Opcode = opcode; switch(encoding) { case OI: if (immediate == I32) { m_Instruction.m_Operand1 = m_Bus->AccessX(m_InstructionPointer + 1); m_Instruction.m_Length = 5; } else if (immediate == I16) { m_Instruction.m_Operand1 = m_Bus->AccessX(m_InstructionPointer + 1); m_Instruction.m_Length = 3; } else if (immediate == I8) { m_Instruction.m_Operand1 = m_Bus->AccessX(m_InstructionPointer + 1); m_Instruction.m_Length = 2; } else { throw CPUException("[CPU] [FetchDecode] OI instruction encoding only supports imm8,imm16,imm32."); } break; case ZO: m_Instruction.m_Length = 1; break; case RM: case MR: { uint8_t modrm = m_Bus->AccessX(m_InstructionPointer + 1); m_Instruction.m_ModRM = x86::ProcessMODRM(modrm); m_Instruction.m_Length = 2; FetchModRMFields(modrm); if (m_Instruction.m_ModRM.m_SIB) { uint8_t sib = m_Bus->AccessX(m_InstructionPointer + m_Instruction.m_Length); m_Instruction.m_Length += 1; m_Instruction.m_SIB = x86::ProcessSIB(sib); } break; } default: throw CPUException("[CPU] [FetchDecode] Encoding was not found!"); } m_Instruction.m_Func = instruction.m_Executor; m_InstructionPointer += m_Instruction.m_Length; } void CPU::Execute() { if(m_Instruction.m_Func != nullptr) { m_Instruction.m_Func(m_Context); return; } throw std::runtime_error("[CPU] [Execute] m_Func is nullptr!"); } void CPU::FetchModRMFields(uint8_t modrm) { assert(m_Instruction.m_Length != 0); // FetchDecode() must set m_Length before calling FetchModRMFields() auto modrm_table = GetMod32Table(); modrm_table[modrm](m_Context); }