2026-02-04 12:52:42 +01:00
|
|
|
#include "CPU.h"
|
|
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <iomanip>
|
2026-02-05 14:57:23 +01:00
|
|
|
#include <bitset>
|
2026-02-04 12:52:42 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <array>
|
2026-02-04 22:28:36 +01:00
|
|
|
#include <cassert>
|
2026-02-04 12:52:42 +01:00
|
|
|
|
2026-02-06 19:20:42 +01:00
|
|
|
CPU::CPU(std::shared_ptr<Bus>& bus) : m_Bus(bus), m_IsHalted(false), m_Context({m_Instruction, m_InstructionPointer, m_Flags, m_Registers, m_Bus, m_IsHalted}) {
|
2026-02-04 12:52:42 +01:00
|
|
|
m_InstructionPointer = 0x00008000;
|
|
|
|
|
|
2026-02-05 14:57:23 +01:00
|
|
|
for(int i = 0; i < 8; i++)
|
2026-02-04 12:52:42 +01:00
|
|
|
{
|
|
|
|
|
m_Registers[i] = 0;
|
|
|
|
|
}
|
2026-02-05 14:57:23 +01:00
|
|
|
|
|
|
|
|
for(int i = 0; i < 8; i++)
|
|
|
|
|
{
|
|
|
|
|
m_SegmentRegisters[i] = 0;
|
|
|
|
|
}
|
2026-02-04 12:52:42 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-04 22:28:36 +01:00
|
|
|
void CPU::Step() {
|
2026-02-04 12:52:42 +01:00
|
|
|
FetchDecode();
|
|
|
|
|
Execute();
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-05 14:57:23 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-06 19:20:42 +01:00
|
|
|
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};
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 22:28:36 +01:00
|
|
|
void CPU::FetchDecode() {
|
|
|
|
|
uint8_t opcode_raw = m_Bus->AccessX<uint8_t>(m_InstructionPointer);
|
|
|
|
|
Opcode opcode = static_cast<Opcode>(opcode_raw);
|
2026-02-04 12:52:42 +01:00
|
|
|
|
2026-02-04 22:28:36 +01:00
|
|
|
switch(opcode_raw) {
|
2026-02-05 00:42:25 +01:00
|
|
|
case Opcode::MOV_R32_IMM32 ... 0xBF: // 0xB8 to 0xBF
|
|
|
|
|
m_Instruction.m_Opcode = Opcode::MOV_R32_IMM32;
|
2026-02-04 22:28:36 +01:00
|
|
|
m_Instruction.m_Operand1 = opcode_raw - 0xB8;
|
2026-02-04 12:52:42 +01:00
|
|
|
m_Instruction.m_Operand2 = m_Bus->AccessX<uint32_t>(m_InstructionPointer + 1);
|
|
|
|
|
m_Instruction.m_Length = 5;
|
|
|
|
|
break;
|
2026-02-04 22:28:36 +01:00
|
|
|
case Opcode::NOP:
|
|
|
|
|
case Opcode::HLT:
|
|
|
|
|
m_Instruction.m_Opcode = opcode;
|
|
|
|
|
m_Instruction.m_Length = 1;
|
2026-02-04 12:52:42 +01:00
|
|
|
break;
|
2026-02-04 22:28:36 +01:00
|
|
|
case Opcode::ADD_RM32_R32:
|
|
|
|
|
m_Instruction.m_Opcode = opcode;
|
|
|
|
|
m_Instruction.optional.m_ModRM = x86::process_modrm(m_Bus->AccessX<uint8_t>(m_InstructionPointer + 1));
|
|
|
|
|
m_Instruction.m_Length = 2;
|
|
|
|
|
FetchModRMFields();
|
2026-02-04 12:52:42 +01:00
|
|
|
break;
|
2026-02-05 14:57:23 +01:00
|
|
|
case Opcode::MOV_RM32_R32:
|
|
|
|
|
m_Instruction.m_Opcode = opcode;
|
|
|
|
|
m_Instruction.optional.m_ModRM = x86::process_modrm(m_Bus->AccessX<uint8_t>(m_InstructionPointer + 1));
|
|
|
|
|
m_Instruction.m_Length = 2;
|
|
|
|
|
FetchModRMFields();
|
|
|
|
|
break;
|
2026-02-04 12:52:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_InstructionPointer += m_Instruction.m_Length;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 22:28:36 +01:00
|
|
|
void CPU::Execute() {
|
2026-02-04 12:52:42 +01:00
|
|
|
uint8_t opcode_value = static_cast<uint8_t>(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!");
|
|
|
|
|
}
|
2026-02-04 22:28:36 +01:00
|
|
|
|
|
|
|
|
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:
|
2026-02-06 19:20:42 +01:00
|
|
|
{
|
|
|
|
|
uint32_t disp = m_Bus->AccessX<uint32_t>(m_InstructionPointer + m_Instruction.m_Length);
|
|
|
|
|
std::memcpy(&m_Instruction.m_Displacement, &disp, 4);
|
|
|
|
|
m_Instruction.m_DisplacementSize = 4;
|
2026-02-04 22:28:36 +01:00
|
|
|
m_Instruction.m_Length += 4;
|
|
|
|
|
break;
|
2026-02-06 19:20:42 +01:00
|
|
|
}
|
2026-02-04 22:28:36 +01:00
|
|
|
case x86::ModRMState::LR_DISP8:
|
2026-02-06 19:20:42 +01:00
|
|
|
m_Instruction.m_Displacement[0] = m_Bus->AccessX<uint8_t>(m_InstructionPointer + m_Instruction.m_Length);
|
|
|
|
|
m_Instruction.m_DisplacementSize = 1;
|
2026-02-04 22:28:36 +01:00
|
|
|
m_Instruction.m_Length += 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw std::runtime_error("Instruction could not be modified according to the modrm field!");
|
|
|
|
|
}
|
|
|
|
|
}
|