#include "CPU.h" #include #include #include #include #include #include #include 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.m_Opcode = (Opcode)0; m_Instruction.m_Operand1 = 0; m_Instruction.m_Operand2 = 0; std::memset(m_Instruction.m_Displacement, 0, 4); m_Instruction.optional.m_ModRM = (x86::ModRM){ .m_State = x86::ModRMState::INVALID, .m_Reg = 0, .m_Rm = 0 }; } CPUStatus CPU::GetStatus() { return (CPUStatus){.m_Registers = m_Registers, .m_IP = m_InstructionPointer, .m_Instruction = m_Instruction}; } void CPU::FetchDecode() { uint8_t opcode_raw = m_Bus->AccessX(m_InstructionPointer); Opcode opcode = static_cast(opcode_raw); switch(opcode_raw) { case Opcode::MOV_R32_IMM32 ... 0xBF: // 0xB8 to 0xBF m_Instruction.m_Opcode = Opcode::MOV_R32_IMM32; m_Instruction.m_Operand1 = opcode_raw - 0xB8; m_Instruction.m_Operand2 = m_Bus->AccessX(m_InstructionPointer + 1); m_Instruction.m_Length = 5; break; case Opcode::NOP: case Opcode::HLT: m_Instruction.m_Opcode = opcode; m_Instruction.m_Length = 1; break; case Opcode::ADD_RM32_R32: m_Instruction.m_Opcode = opcode; m_Instruction.optional.m_ModRM = x86::process_modrm(m_Bus->AccessX(m_InstructionPointer + 1)); m_Instruction.m_Length = 2; FetchModRMFields(); break; case Opcode::MOV_RM32_R32: m_Instruction.m_Opcode = opcode; m_Instruction.optional.m_ModRM = x86::process_modrm(m_Bus->AccessX(m_InstructionPointer + 1)); m_Instruction.m_Length = 2; FetchModRMFields(); break; } m_InstructionPointer += m_Instruction.m_Length; } void CPU::Execute() { uint8_t opcode_value = static_cast(m_Instruction.m_Opcode); auto& exec_table = GetExecutorTable(); if(exec_table[opcode_value]) { exec_table[opcode_value](m_Context); return; } throw std::runtime_error("Opcode not found!"); } void CPU::FetchModRMFields() { assert(m_Instruction.m_Length != 0); // FetchDecode() must set m_Length before calling FetchModRMFields() x86::ModRMState state = m_Instruction.optional.m_ModRM.m_State; switch(state) { case x86::ModRMState::LR: case x86::ModRMState::R: break; case x86::ModRMState::DISP32: case x86::ModRMState::LR_DISP32: { uint32_t disp = m_Bus->AccessX(m_InstructionPointer + m_Instruction.m_Length); std::memcpy(&m_Instruction.m_Displacement, &disp, 4); m_Instruction.m_DisplacementSize = 4; m_Instruction.m_Length += 4; break; } case x86::ModRMState::LR_DISP8: m_Instruction.m_Displacement[0] = m_Bus->AccessX(m_InstructionPointer + m_Instruction.m_Length); m_Instruction.m_DisplacementSize = 1; m_Instruction.m_Length += 1; break; default: throw std::runtime_error("Instruction could not be modified according to the modrm field!"); } }