Refactor: Fetch-Decode phase is instruction-agnostic and operand-encoding dependant

This commit is contained in:
0x221E
2026-02-07 00:16:48 +01:00
parent 71f516b564
commit 3e1e19023d
7 changed files with 123 additions and 57 deletions

View File

@@ -11,13 +11,11 @@
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}) {
m_InstructionPointer = 0x00008000;
for(int i = 0; i < 8; i++)
{
for(int i = 0; i < 8; i++) {
m_Registers[i] = 0;
}
for(int i = 0; i < 8; i++)
{
for(int i = 0; i < 8; i++) {
m_SegmentRegisters[i] = 0;
}
}
@@ -50,6 +48,7 @@ void CPU::Reset() {
m_Registers[i] = 0;
m_SegmentRegisters[i] = 0;
}
m_InstructionPointer = 0x8000;
m_Flags = 0;
@@ -58,6 +57,7 @@ void CPU::Reset() {
m_Instruction.m_Opcode = (Opcode)0;
m_Instruction.m_Operand1 = 0;
m_Instruction.m_Operand2 = 0;
m_Instruction.m_Func = nullptr;
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 };
}
@@ -70,44 +70,60 @@ void CPU::FetchDecode() {
uint8_t opcode_raw = m_Bus->AccessX<uint8_t>(m_InstructionPointer);
Opcode opcode = static_cast<Opcode>(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<uint32_t>(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<uint8_t>(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<uint8_t>(m_InstructionPointer + 1));
m_Instruction.m_Length = 2;
FetchModRMFields();
break;
auto& instruction_table = GetInstructionTable();
if(instruction_table[opcode_raw].m_Executor == nullptr) {
std::cout << "Encoding: " << opcode_raw << std::endl;
throw std::runtime_error("[CPU] [FetchDecode] Opcode is not in instruction table!");
}
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;
switch(encoding) {
case OI:
if (immediate == I32) {
m_Instruction.m_Operand1 = m_Bus->AccessX<uint32_t>(m_InstructionPointer + 1);
m_Instruction.m_Length = 5;
} else if (immediate = I16) {
m_Instruction.m_Operand1 = m_Bus->AccessX<uint16_t>(m_InstructionPointer + 1);
m_Instruction.m_Length = 3;
} else if (immediate = I8) {
m_Instruction.m_Operand1 = m_Bus->AccessX<uint8_t>(m_InstructionPointer + 1);
m_Instruction.m_Length = 2;
} else {
throw std::runtime_error("[CPU] [FetchDecode] OI instruction encoding only supports imm8,imm16,imm32.");
}
break;
case ZO:
m_Instruction.m_Length = 1;
break;
case RM:
case MR:
m_Instruction.optional.m_ModRM = x86::process_modrm(m_Bus->AccessX<uint8_t>(m_InstructionPointer + 1));
m_Instruction.m_Length = 2;
FetchModRMFields();
break;
default:
throw std::runtime_error("[CPU] [FetchDecode] Encoding was not found!");
}
m_Instruction.m_Func = instruction.m_Executor;
m_Instruction.m_Opcode = opcode;
m_InstructionPointer += m_Instruction.m_Length;
}
void CPU::Execute() {
uint8_t opcode_value = static_cast<uint8_t>(m_Instruction.m_Opcode);
auto& exec_table = GetExecutorTable();
if(exec_table[opcode_value])
if(m_Instruction.m_Func != nullptr)
{
exec_table[opcode_value](m_Context);
m_Instruction.m_Func(m_Context);
return;
}
throw std::runtime_error("Opcode not found!");
throw std::runtime_error("[CPU] [Execute] m_Func is nullptr!");
}
void CPU::FetchModRMFields() {