summaryrefslogtreecommitdiff
path: root/src/CPU.cpp
diff options
context:
space:
mode:
author0x221E <0x221E@0xinfinity.dev>2026-04-12 16:59:40 +0200
committer0x221E <0x221E@0xinfinity.dev>2026-04-12 16:59:40 +0200
commita66c7433c2c11b8b6c99142277ed4e16b1a2a465 (patch)
treee54bcfb59c303acf6118fd11f06d5c0bd5f24e5d /src/CPU.cpp
initial commitHEADmaster
Diffstat (limited to 'src/CPU.cpp')
-rw-r--r--src/CPU.cpp142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/CPU.cpp b/src/CPU.cpp
new file mode 100644
index 0000000..dd03a19
--- /dev/null
+++ b/src/CPU.cpp
@@ -0,0 +1,142 @@
+#include "CPU.h"
+
+#include <stdexcept>
+#include <iostream>
+#include <iomanip>
+#include <bitset>
+#include <stdlib.h>
+#include <array>
+#include <cassert>
+
+#include "Exceptions.h"
+#include "InstructionModifierLookup.h"
+
+static const Instruction s_EmptyInstruction{};
+
+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++) {
+ 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<uint8_t>(m_InstructionPointer);
+ Opcode opcode = static_cast<Opcode>(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<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 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<uint8_t>(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<uint8_t>(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);
+}