// Emulator.cpp
#include "Emulator.h"
#include <iostream>
#include <algorithm>

// Конструктор
Emulator::Emulator(size_t memory_size) {
    memory.resize(memory_size, 0);
    initialize_instruction_set();
    regs.ESP = static_cast<uint32_t>(memory_size);
    // Инициализируем сегментные регистры (по умолчанию можно установить базу 0)
    regs.CS = 0;
    regs.DS = 0;
    regs.SS = memory_size; // Стек начинается в конце памяти
    regs.ES = 0;
    regs.FS = 0;
    regs.GS = 0;

    // Устанавливаем текущие сегменты на сегменты по умолчанию
    current_data_segment = &regs.DS;
    current_code_segment = &regs.CS;
}
void Emulator::set_segment_override(uint8_t prefix) {
    switch (prefix) {
    case 0x2E: // CS
        current_code_segment = &regs.CS;
        break;
    case 0x36: // SS
        current_data_segment = &regs.SS;
        break;
    case 0x3E: // DS
        current_data_segment = &regs.DS;
        break;
    case 0x26: // ES
        current_data_segment = &regs.ES;
        break;
    case 0x64: // FS
        current_data_segment = &regs.FS;
        break;
    case 0x65: // GS
        current_data_segment = &regs.GS;
        break;
    default:
        // Неизвестный префикс сегмента, можно игнорировать или установить ошибку
        std::cout << "Неизвестный сегментный префикс: 0x" << std::hex << (int)prefix << "\n";
        break;
    }
}
// Реализация метода write_memory
void Emulator::write_memory(uint32_t address, const uint8_t* data, size_t size) {
    if (address + size > memory.size()) {
        std::cerr << "Ошибка: Пытаетесь записать за пределы памяти. Адрес: 0x"
            << std::hex << address << ", Размер: " << std::dec << size << "\n";
        error_flag = true;
        running = false;
        return;
    }
    std::memcpy(&memory[address], data, size);
}
// Реализация метода set_eip
void Emulator::set_eip(uint32_t address) {
    if (address >= memory.size()) {
        std::cerr << "Ошибка: Установка EIP за пределами памяти. Адрес: 0x"
            << std::hex << address << "\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.EIP = address;
}
uint8_t Emulator::read_memory_byte(uint32_t address) const {
    if (address >= memory.size()) {
        throw std::runtime_error("Чтение памяти вне границ");
    }
    return memory[address];
}

uint32_t Emulator::read_memory_dword(uint32_t address) const {
    if (address + 4 > memory.size()) {
        throw std::runtime_error("Чтение памяти вне границ");
    }
    uint32_t value = 0;
    value |= static_cast<uint32_t>(memory[address]);
    value |= static_cast<uint32_t>(memory[address + 1]) << 8;
    value |= static_cast<uint32_t>(memory[address + 2]) << 16;
    value |= static_cast<uint32_t>(memory[address + 3]) << 24;
    return value;
}

// Метод load_program
void Emulator::load_program(const std::vector<uint8_t>& program, size_t load_address, bool set_eip) {
    if (load_address + program.size() > memory.size()) {
        throw std::runtime_error("Размер программы превышает лимиты памяти");
    }
    std::copy(program.begin(), program.end(), memory.begin() + load_address);
    if (set_eip) {
        regs.EIP = load_address;
    }
}

// Метод run
void Emulator::run() {
    running = true;
    while (running) {
        try {
            uint8_t opcode = fetch_byte();

            // Список префиксов
            const std::vector<uint8_t> prefixes = {
                0xF2, // REPNE/REPNZ
                0xF3, // REP/REPE/REPZ
                0xF0, // LOCK
                0x2E, // CS segment override
                0x36, // SS segment override
                0x3E, // DS segment override
                0x26, // ES segment override
                0x64, // FS segment override
                0x65, // GS segment override
                0x66, // Operand-size override
                0x67  // Address-size override
            };

            // Сбор префиксов
            while (std::find(prefixes.begin(), prefixes.end(), opcode) != prefixes.end()) {
                switch (opcode) {
                case 0xF2:
                    regs.repne_prefix = true;
                    break;
                case 0xF3:
                    regs.rep_prefix = true;
                    break;
                case 0xF0:
                    regs.lock_prefix = true;
                    break;
                case 0x66:
                    regs.operand_size_override = true;
                    break;
                case 0x67:
                    regs.address_size_override = true;
                    break;
                case 0x2E:
                case 0x36:
                case 0x3E:
                case 0x26:
                case 0x64:
                case 0x65:
                    set_segment_override(opcode);
                    break;
                default:
                    break;
                }

                std::cout << "Обнаружен префикс: 0x" << std::hex << (int)opcode << "\n";

                // Проверяем на ENDBR32
                if (opcode == 0xF3) {
                    uint8_t next_opcode = memory[regs.EIP];
                    if (next_opcode == 0x0F) {
                        // Потенциально ENDBR32, прерываем сбор префиксов
                        break;
                    }
                }

                opcode = fetch_byte(); // Читаем следующий байт как опкод инструкции
            }

            // Проверяем на ENDBR32
            if (regs.rep_prefix && memory[regs.EIP] == 0x0F) {
                regs.EIP++; // Пропускаем 0x0F
                uint8_t opcode1 = fetch_byte(); // Считываем следующий байт
                if (opcode1 == 0x1E) {
                    instr_ENDBR32();
                    continue; // Переходим к следующей инструкции
                }
                else {
                    std::cout << "Неизвестный opcode: 0x" << std::hex << (int)opcode1 << "\n";
                    error_flag = true;
                    running = false;
                    continue;
                }
            }

            // Проверка на двухбайтовый опкод
            bool is_extended = false;
            if (opcode == 0x0F) {
                is_extended = true;
                opcode = fetch_byte(); // Читаем второй байт опкода
            }

            if (is_extended) {
                auto it = extended_instruction_set.find(opcode);
                if (it != extended_instruction_set.end()) {
                    InstructionHandler handler = it->second;
                    (this->*handler)();
                }
                else {
                    std::cout << "Неизвестный двухбайтовый opcode: 0x0F 0x"
                        << std::hex << (int)opcode << "\n";
                    error_flag = true;
                    running = false;
                }
            }
            else {
                auto it = instruction_set.find(opcode);
                if (it != instruction_set.end()) {
                    InstructionHandler handler = it->second;
                    (this->*handler)();
                }
                else {
                    std::cout << "Неизвестный opcode: 0x" << std::hex << (int)opcode << "\n";
                    error_flag = true;
                    running = false;
                }
            }

            // После выполнения инструкции сбросить префиксы
            reset_segment_override();
            reset_prefixes();

        }
        catch (const std::exception& e) {
            std::cerr << "Exception caught: " << e.what() << "\n";
            error_flag = true;
            running = false;
        }
    }
}

void Emulator::reset_prefixes() {
    regs.lock_prefix = false;
    regs.rep_prefix = false;
    regs.repne_prefix = false;
    regs.operand_size_override = false;
    regs.address_size_override = false;
    // Сброс других префиксов при необходимости
}
void Emulator::reset_segment_override() {
    // Сброс текущих сегментов к стандартным значениям
    current_data_segment = &regs.DS;
    current_code_segment = &regs.CS;
}
// Метод print_registers
void Emulator::print_registers(bool hex_output) const {
    if (hex_output) {
        std::cout << std::hex;
        std::cout << "EAX: 0x" << regs.EAX << "\n";
        std::cout << "EBX: 0x" << regs.EBX << "\n";
        std::cout << "ECX: 0x" << regs.ECX << "\n";
        std::cout << "EDX: 0x" << regs.EDX << "\n";
        std::cout << "ESI: 0x" << regs.ESI << "\n";
        std::cout << "EDI: 0x" << regs.EDI << "\n";
        std::cout << "ESP: 0x" << regs.ESP << "\n";
        std::cout << "EBP: 0x" << regs.EBP << "\n";
        std::cout << "EIP: 0x" << regs.EIP << "\n";
        std::cout << "EFLAGS: 0x" << regs.EFLAGS << "\n";
        std::cout << std::dec; // Возвращаемся к десятичной системе счисления
    }
    else {
        std::cout << "EAX: " << regs.EAX << "\n";
        std::cout << "EBX: " << regs.EBX << "\n";
        std::cout << "ECX: " << regs.ECX << "\n";
        std::cout << "EDX: " << regs.EDX << "\n";
        std::cout << "ESI: " << regs.ESI << "\n";
        std::cout << "EDI: " << regs.EDI << "\n";
        std::cout << "ESP: " << regs.ESP << "\n";
        std::cout << "EBP: " << regs.EBP << "\n";
        std::cout << "EIP: " << regs.EIP << "\n";
        std::cout << "EFLAGS: " << regs.EFLAGS << "\n";
    }
}

uint32_t Emulator::calculate_sib_address(uint8_t mod, uint8_t sib, int32_t displacement) {
    uint8_t scale = (sib >> 6) & 0x03;
    uint8_t index = (sib >> 3) & 0x07;
    uint8_t base = sib & 0x07;

    uint32_t base_value = 0;
    uint32_t index_value = 0;

    // Получаем значение base
    if (base == 5) {
        if (mod == 0) {
            // base = 0, disp32 используется вместо base
            base_value = 0;
            displacement += fetch_dword(); // Дополнительный disp32
        }
        else {
            base_value = *get_register_by_code(base);
        }
    }
    else {
        base_value = *get_register_by_code(base);
    }

    // Получаем значение index
    if (index != 4) { // Если index не равно 4 (4 означает, что index не используется)
        index_value = *get_register_by_code(index) << scale;
    }

    uint32_t address = base_value + index_value + displacement;
    return address;
}

uint32_t Emulator::calculate_address(uint8_t modrm) {
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;
    std::cout << "calculate_address called with mod=" << (int)mod << ", rm=" << (int)rm << "\n";
    uint32_t address = 0;

    if (mod == 0) {
        if (rm == 5) {
            // [disp32]
            uint32_t disp32 = fetch_dword();
            address = disp32;
        }
        else if (rm == 4) {
            // SIB byte
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, 0);
        }
        else {
            // [reg]
            address = *get_register_by_code(rm);
        }
    }
    else if (mod == 1) {
        int8_t disp8 = static_cast<int8_t>(fetch_byte());
        if (rm == 4) {
            // SIB byte с disp8
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp8);
        }
        else {
            // [reg + disp8]
            address = *get_register_by_code(rm) + disp8;
        }
    }
    else if (mod == 2) {
        int32_t disp32 = static_cast<int32_t>(fetch_dword());
        if (rm == 4) {
            // SIB byte с disp32
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp32);
        }
        else {
            // [reg + disp32]
            address = *get_register_by_code(rm) + disp32;
        }
    }
    else if (mod == 3) {
        // Mod == 3 indicates register-direct mode, address calculation is not applicable.
        std::cout << "Error: calculate_address() called with mod == 3 (register-direct mode) which is invalid for memory addressing.\n";
        error_flag = true;
        running = false;
        return 0;
    }
    else {
        std::cout << "Unsupported ModR/M mod value in calculate_address.\n";
        error_flag = true;
        running = false;
        return 0;
    }

    // Добавьте базу сегмента к вычисленному адресу
    // Для Data Segment
    address += *current_data_segment;

    if (address >= memory.size()) {
        std::cout << "Address out of bounds: 0x" << std::hex << address << "\n";
        error_flag = true;
        running = false;
    }

    return address;
}

// Инициализация таблицы инструкций
void Emulator::initialize_instruction_set() {
    instruction_set[0xB8] = &Emulator::instr_MOV_EAX_imm32;   
    instruction_set[0xB9] = &Emulator::instr_MOV_ECX_imm32;
    instruction_set[0xBA] = &Emulator::instr_MOV_EDX_imm32;
    instruction_set[0x05] = &Emulator::instr_ADD_EAX_imm32;
    instruction_set[0x2D] = &Emulator::instr_SUB_EAX_imm32;
    instruction_set[0x40] = &Emulator::instr_INC_EAX;
    instruction_set[0x48] = &Emulator::instr_DEC_EAX;
    instruction_set[0xF7] = &Emulator::instr_F7;
    instruction_set[0xE9] = &Emulator::instr_JMP_rel32;
    instruction_set[0x83] = &Emulator::instr_GROUP1_Ev_Iz_83;
    instruction_set[0x74] = &Emulator::instr_JE_rel8;
    instruction_set[0x75] = &Emulator::instr_JNE_rel8;
    instruction_set[0x25] = &Emulator::instr_AND_EAX_imm32;
    instruction_set[0x21] = &Emulator::instr_AND_ECX_imm32;
    instruction_set[0x0D] = &Emulator::instr_OR_EAX_imm32;
    instruction_set[0x35] = &Emulator::instr_XOR_EAX_imm32;
    instruction_set[0x81] = &Emulator::instr_GROUP1_Ev_Iz_81;
    instruction_set[0x3D] = &Emulator::instr_CMP_EAX_imm32;
    instruction_set[0x0E] = &Emulator::instr_OR_ECX_imm32;
    instruction_set[0xC3] = &Emulator::instr_RET; // Обработчик RET
    instruction_set[0xA3] = &Emulator::instr_MOV_MEM_EAX; // MOV [address], EAX
    instruction_set[0xA1] = &Emulator::instr_MOV_EAX_MEM; // MOV EAX, [address]
    instruction_set[0xCD] = &Emulator::instr_INT; // INT n
    instruction_set[0x89] = &Emulator::instr_MOV_r32_rm32;
    instruction_set[0x31] = &Emulator::instr_XOR_r32_rm32;
    instruction_set[0x04] = &Emulator::instr_ADD_AL_imm8;
    instruction_set[0x88] = &Emulator::instr_MOV_rm8_r8;
    instruction_set[0xC6] = &Emulator::instr_MOV_rm8_imm8;
    instruction_set[0x39] = &Emulator::instr_CMP_r32_rm32; // CMP r/m32, r32
    instruction_set[0x7F] = &Emulator::instr_JG_rel8;     // JG rel8
    instruction_set[0x7C] = &Emulator::instr_JL_rel8;     // JL rel8
    instruction_set[0x8A] = &Emulator::instr_MOV_r8_rm8;
    instruction_set[0x80] = &Emulator::instr_SUB_rm8_imm8;
    instruction_set[0xB7] = &Emulator::instr_MOV_r8_imm8;
    instruction_set[0x69] = &Emulator::instr_IMUL_reg_rm32_imm32;
    instruction_set[0x72] = &Emulator::instr_JB_rel8;
    instruction_set[0x77] = &Emulator::instr_JA_rel8;
    instruction_set[0x41] = &Emulator::instr_INC_ECX;
    instruction_set[0xEB] = &Emulator::instr_JMP_rel8;
    instruction_set[0x2C] = &Emulator::instr_SUB_AL_imm8;
    instruction_set[0x3C] = &Emulator::instr_CMP_AL_imm8;
    instruction_set[0x01] = &Emulator::instr_ADD_rm32_r32;
    instruction_set[0x03] = &Emulator::instr_ADD_r32_rm32; // ADD r32, r/m32
    instruction_set[0x6B] = &Emulator::instr_IMUL_reg_rm32_imm8;
    instruction_set[0x8B] = &Emulator::instr_MOV_r32_r_m32; // Добавляем обработчик для MOV r32, r/m32
    instruction_set[0xBB] = &Emulator::instr_MOV_EBX_imm32;
    instruction_set[0xBD] = &Emulator::instr_MOV_EBP_imm32; // MOV EBP, imm32
    instruction_set[0xBC] = &Emulator::instr_MOV_ESP_imm32; // MOV ESP, imm32
    instruction_set[0xBE] = &Emulator::instr_MOV_ESI_imm32;
    instruction_set[0xBF] = &Emulator::instr_MOV_EDI_imm32; // MOV EDI, imm32
    instruction_set[0xE8] = &Emulator::instr_CALL_rel32; // MOV rel32, CALL rel32
    instruction_set[0x8D] = &Emulator::instr_LEA_r32_m;
    instruction_set[0xA4] = &Emulator::instr_MOVSB; // MOVSB opcode
    instruction_set[0x5E] = &Emulator::instr_POP_ESI;
    extended_instruction_set[0x84] = &Emulator::instr_JE_rel32;
    extended_instruction_set[0x85] = &Emulator::instr_JNE_rel32;
    extended_instruction_set[0x8F] = &Emulator::instr_JG_rel32;
    extended_instruction_set[0x8C] = &Emulator::instr_JL_rel32;
    extended_instruction_set[0x1E] = &Emulator::instr_NOP_m16_m32;
    extended_instruction_set[0x1E] = &Emulator::instr_ENDBR32;
    instruction_set[0xFB] = &Emulator::instr_STI;
}
Emulator::Operand Emulator::decode_operand(uint8_t modrm) {
    Operand operand;
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;

    if (mod == 3) { // Регистр-режим
        operand.is_memory = false;
        operand.register_code = rm;
    }
    else { // Память
        operand.is_memory = true;
        operand.address = calculate_address(modrm);
    }

    return operand;
}
void Emulator::instr_IMUL_reg_rm32_imm8() {
    // Fetch ModRM byte
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Destination register
    uint8_t rm_code = modrm & 0x07;         // Source operand

    uint32_t* dest_reg = get_register_by_code(reg_code);
    uint32_t operand = 0;

    // Determine the operand based on addressing mode
    if (mod == 3) { // Register-direct mode
        uint32_t* src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            std::cout << "Unknown source register in IMUL.\n";
            error_flag = true;
            running = false;
            return;
        }
        operand = *src_reg;
    }
    else {
        // For simplicity, handle only register-direct mode
        std::cout << "Unsupported addressing mode in IMUL.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Fetch immediate 8-bit value
    int8_t imm8 = static_cast<int8_t>(fetch_byte());

    // Perform multiplication
    int32_t result = static_cast<int32_t>(operand) * imm8;
    *dest_reg = static_cast<uint32_t>(result);

    // Update flags as necessary
    update_ZF(*dest_reg);
    // Update other flags (CF, OF) if necessary
}
void Emulator::write_memory_byte(uint32_t address, uint8_t value) {
    if (address >= memory.size()) {
        std::cerr << "Ошибка: Пытаетесь записать byte за пределы памяти. Адрес: 0x"
            << std::hex << address << std::dec << "\n";
        error_flag = true;    // Устанавливаем флаг ошибки
        running = false;      // Останавливаем выполнение эмулятора
        return;
    }
    memory[address] = value;  // Записываем байт в память
}
void Emulator::write_memory_dword(uint32_t address, uint32_t value) {
    if (address + 4 > memory.size()) {
        std::cerr << "Ошибка: Память для записи dword выходит за пределы. Адрес: 0x"
            << std::hex << address << "\n";
        error_flag = true;
        running = false;
        return;
    }
    memory[address] = value & 0xFF;
    memory[address + 1] = (value >> 8) & 0xFF;
    memory[address + 2] = (value >> 16) & 0xFF;
    memory[address + 3] = (value >> 24) & 0xFF;
}

// Обновление Zero Flag (ZF)
void Emulator::update_ZF(uint32_t result) {
    if (result == 0)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;
}

// Вспомогательные методы

uint8_t Emulator::fetch_byte() {
    if (regs.EIP >= memory.size()) {
        throw std::runtime_error("EIP вне границ памяти");
    }
    return memory[regs.EIP++];
}

// Реализация fetch_dword с проверкой увеличения EIP
uint32_t Emulator::fetch_dword() {
    if (regs.EIP + 4 > memory.size()) {
        throw std::runtime_error("EIP вне границ памяти для загрузки dword");
    }
    uint32_t value = 0;
    // x86 uses little endian
    value = static_cast<uint32_t>(memory[regs.EIP]) |
        (static_cast<uint32_t>(memory[regs.EIP + 1]) << 8) |
        (static_cast<uint32_t>(memory[regs.EIP + 2]) << 16) |
        (static_cast<uint32_t>(memory[regs.EIP + 3]) << 24);

    regs.EIP += 4;

    return value;
}

uint32_t* Emulator::get_register_by_code(uint8_t code) {
    switch (code) {
    case 0: return &regs.EAX;
    case 1: return &regs.ECX;
    case 2: return &regs.EDX;
    case 3: return &regs.EBX;
    case 4: return &regs.ESP;
    case 5: return &regs.EBP;
    case 6: return &regs.ESI;
    case 7: return &regs.EDI;
    default: return nullptr;
    }
}

uint8_t* Emulator::get_register8_by_code(uint8_t code) {
    switch (code) {
    case 0: return reinterpret_cast<uint8_t*>(&regs.EAX);          // AL
    case 1: return reinterpret_cast<uint8_t*>(&regs.ECX);          // CL
    case 2: return reinterpret_cast<uint8_t*>(&regs.EDX);          // DL
    case 3: return reinterpret_cast<uint8_t*>(&regs.EBX);          // BL
    case 4: return reinterpret_cast<uint8_t*>(&regs.EAX) + 1;      // AH
    case 5: return reinterpret_cast<uint8_t*>(&regs.ECX) + 1;      // CH
    case 6: return reinterpret_cast<uint8_t*>(&regs.EDX) + 1;      // DH
    case 7: return reinterpret_cast<uint8_t*>(&regs.EBX) + 1;      // BH
    default: return nullptr;
    }
}

uint8_t Emulator::regm_rm(uint8_t modrm) {
    return modrm & 0x07; // Извлекаем регистровый код (rm)
}
// Instructions.cpp
#include "Emulator.h"
#include <iostream>
#include <stdint.h>
#include <string>
// Реализация обработчиков инструкций

// MOV EAX, imm32
void Emulator::instr_MOV_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX = imm;
}
void Emulator::instr_NOP_EAX() {
    // Эта инструкция ничего не делает, можно просто вывести сообщение
    std::cout << "Выполнен NOP [EAX]\n";
}
void Emulator::instr_STI() {
    // Устанавливаем флаг прерываний (IF)
    regs.EFLAGS |= IF_FLAG;
    std::cout << "Выполнен STI: Установлен флаг прерываний (IF).\n";
}
void Emulator::instr_POP_ESI() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP ESI.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Считываем значение со стека и сохраняем его в регистр ESI
    regs.ESI = read_memory_dword(regs.ESP);
    regs.ESP += 4;  // Увеличиваем указатель стека

    std::cout << "Выполнен POP ESI. Значение в регистре ESI: " << std::hex << regs.ESI << "\n";
}

void Emulator::instr_ENDBR32() {
    // Мы уже обработали префикс 0xF3 и прочитали опкод 0x0F
    // Теперь нужно убедиться, что следующий байт 0x1E, уже считан
    // Считываем последний байт инструкции
    uint8_t modrm = fetch_byte();
    if (modrm != 0xFB) {
        std::cout << "Ожидаемый байт 0xFB не найден после opcode 0x1E для ENDBR32.\n";
        error_flag = true;
        running = false;
        return;
    }
    // Инструкция корректно распознана, выполняем NOP
    std::cout << "Выполнена инструкция ENDBR32 (пропущена).\n";
}
void Emulator::instr_NOP_m16_m32() {
    // Инструкция NOP m16/32 имеет модификатор размера операнда
    // Если установлен префикс 0x66, то размер операнда 16 бит, иначе 32 бита
    bool operand_size = regs.operand_size_override;

    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;

    if (mod == 3) {
        // Mod == 3 означает, что операнд — регистр
        // В этом случае NOP не делает ничего
        uint8_t rm = modrm & 0x07;
        // Можно просто считать регистр для эмуляции чтения
        uint32_t* reg = get_register_by_code(rm);
        if (reg) {
            uint32_t temp = *reg;
            // NOP ничего не делает, поэтому не изменяем значение
        }
        else {
            std::cout << "Неизвестный регистр в NOP r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        // Если Mod != 3, то вычисляем адрес и читаем операнд из памяти
        uint32_t address = calculate_address(modrm);

        if (operand_size) {
            // Чтение 16-битного операнда для NOP m16
            uint16_t temp = read_memory_byte(address) | (read_memory_byte(address + 1) << 8);
            // NOP не изменяет ничего, просто читаем для эмуляции
        }
        else {
            // Чтение 32-битного операнда для NOP m32
            uint32_t temp = read_memory_dword(address);
            // NOP не изменяет ничего, просто читаем для эмуляции
        }
    }

    // NOP ничего не делает, поэтому ничего не изменяем
}
// MOV EBX, imm32
void Emulator::instr_MOV_EBX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBX = imm;
}

// MOV ECX, imm32
void Emulator::instr_MOV_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX = imm;
}

// MOV EDX, imm32
void Emulator::instr_MOV_EDX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EDX = imm;
}

// ADD EAX, imm32
void Emulator::instr_ADD_EAX_imm32() {
    if (regs.rep_prefix || regs.repne_prefix) {
        std::cout << "Warning: REP prefix is ignored for ADD EAX, imm32.\n";
        reset_prefixes();
    }
    uint32_t imm = fetch_dword();
    std::cout << "Executing ADD EAX, " << imm << " (Before EAX: " << regs.EAX << ")\n";
    regs.EAX += imm;
    std::cout << "After EAX: " << regs.EAX << "\n";
    update_ZF(regs.EAX);
}



// SUB EAX, imm32
void Emulator::instr_SUB_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX -= imm;
    update_ZF(regs.EAX);
}

// INC EAX
void Emulator::instr_INC_EAX() {
    regs.EAX += 1;
    update_ZF(regs.EAX);
}

// DEC EAX
void Emulator::instr_DEC_EAX() {
    regs.EAX -= 1;
    update_ZF(regs.EAX);
}

// MUL EAX
void Emulator::instr_MUL_EAX() {
    uint8_t modrm = fetch_byte();
    // Для простоты реализуем только MUL EAX
    if ((modrm & 0x38) == 0x20) { // Проверяем, что это MUL r/m32
        regs.EAX *= regs.EAX;
        update_ZF(regs.EAX);
    }
    else {
        std::cout << "MUL instruction with unsupported operand.\n";
        // Можно установить флаг ошибки или завершить выполнение
    }
}

// JMP rel32
void Emulator::instr_JMP_rel32() {
    int32_t rel = fetch_dword();
    regs.EIP += rel;
}

// CMP регистр, imm8
void Emulator::instr_CMP_reg_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t imm8 = fetch_byte();
    uint32_t* reg_ptr = get_register_by_code(regm_rm(modrm));
    if (reg_ptr) {
        uint32_t result = *reg_ptr - imm8;

        // Zero Flag
        if (result == 0)
            regs.EFLAGS |= ZF;
        else
            regs.EFLAGS &= ~ZF;

        // Carry Flag
        if (*reg_ptr < imm8)
            regs.EFLAGS |= CF;
        else
            regs.EFLAGS &= ~CF;

        // Sign Flag (SF)
        if (result & (1 << 31))
            regs.EFLAGS |= (1 << 7); // Предполагаем, что SF находится в бит 7
        else
            regs.EFLAGS &= ~(1 << 7);

        // Overflow Flag (OF) - необходимо корректно реализовать
        // Здесь может быть упрощение, для точной реализации требуется дополнительная логика
    }
    else {
        std::cout << "CMP instruction with unsupported register.\n";
        // Можно установить флаг ошибки или завершить выполнение
    }
}

// JE rel8
void Emulator::instr_JE_rel8() {
    int8_t rel = fetch_byte();
    if (regs.EFLAGS & ZF) {
        regs.EIP += rel;
    }
}

// JNE rel8
void Emulator::instr_JNE_rel8() {
    int8_t rel = fetch_byte();
    if (!(regs.EFLAGS & ZF)) {
        regs.EIP += rel;
    }
}

// AND EAX, imm32
void Emulator::instr_AND_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX &= imm;
    update_ZF(regs.EAX);
}

// AND ECX, imm32
void Emulator::instr_AND_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX &= imm;
    update_ZF(regs.ECX);
}

// OR EAX, imm32
void Emulator::instr_OR_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX |= imm;
    update_ZF(regs.EAX);
}

// OR ECX, imm32
void Emulator::instr_OR_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX |= imm;
    update_ZF(regs.ECX);
}

// XOR EAX, imm32
void Emulator::instr_XOR_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX ^= imm;
    update_ZF(regs.EAX);
}

// SUB EBX, imm32
void Emulator::instr_SUB_EBX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBX -= imm;
    update_ZF(regs.EBX);
}

// CMP EAX, imm32
void Emulator::instr_CMP_EAX_imm32() {
    uint32_t imm = fetch_dword();
    uint32_t result = regs.EAX - imm;
    if (regs.EAX == imm)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;
    // Дополнительно можно установить другие флаги (CF, OF и т.д.)
}

// Обработчик инструкции RET
void Emulator::instr_RET() {
    if (regs.ESP + 4 > memory.size()) {
        std::cout << "Stack underflow on RET.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Pop the return address from the stack
    uint32_t return_address = read_memory_dword(regs.ESP);
    regs.ESP += 4;

    // Jump to the return address
    regs.EIP = return_address;
}

// Обработчик инструкции SUB r32, imm32
void Emulator::instr_SUB_r32_imm32() {
    uint8_t modrm = fetch_byte();
    uint8_t reg_opcode = (modrm >> 3) & 0x07; // Извлекаем поле reg из ModRM

    if (reg_opcode != 5) { // Для инструкции SUB reg, imm32, reg_opcode должен быть 5
        std::cout << "Unsupported SUB instruction with reg opcode: " << (int)reg_opcode << "\n";
        return;
    }

    uint32_t imm32 = fetch_dword(); // Извлекаем непосредственное значение
    uint8_t rm = regm_rm(modrm); // Извлекаем регистр назначения из ModRM
    uint32_t* reg_ptr = get_register_by_code(rm);

    if (reg_ptr) {
        *reg_ptr -= imm32;
        update_ZF(*reg_ptr);
    }
    else {
        std::cout << "SUB instruction with unsupported register.\n";
    }
}
void Emulator::instr_CMP_r32_rm32() {
    uint8_t modrm = fetch_byte();

    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Источник: r32
    uint8_t rm_code = modrm & 0x07;         // Назначение: r/m32

    uint32_t* reg = get_register_by_code(reg_code); // Источник
    uint32_t* rm;

    if (mod == 3) {
        rm = get_register_by_code(rm_code);

        if (!rm) {
            std::cout << "Неизвестный регистр в CMP r/m32, r32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        // Для простоты реализуем только регистровый режим
        std::cout << "Поддерживается только регистровый режим для CMP r/m32, r32.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Выполняем сравнение
    uint32_t result = *rm - *reg;

    // Обновляем флаги
    // Zero Flag (ZF)
    if (result == 0)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;

    // Sign Flag (SF)
    if (result & 0x80000000)
        regs.EFLAGS |= SF;
    else
        regs.EFLAGS &= ~SF;

    // Carry Flag (CF)
    if (*rm < *reg)
        regs.EFLAGS |= CF;
    else
        regs.EFLAGS &= ~CF;

    // Overflow Flag (OF)
    uint32_t sign_rm = *rm & 0x80000000;
    uint32_t sign_reg = *reg & 0x80000000;
    uint32_t sign_result = result & 0x80000000;
    if ((sign_rm != sign_reg) && (sign_rm != sign_result))
        regs.EFLAGS |= OF;
    else
        regs.EFLAGS &= ~OF;
}
// Обработчик инструкции JE rel32 (0x0F 0x84)
void Emulator::instr_JE_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    if (regs.EFLAGS & ZF) { // Проверка флага равенства
        regs.EIP += rel32;
    }
}

// Обработчик инструкции JNE rel32 (0x0F 0x85)
void Emulator::instr_JNE_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    if (!(regs.EFLAGS & ZF)) { // Проверка флага неравенства
        regs.EIP += rel32;
    }
}

// Обработчик инструкции JG rel32 (0x0F 0x8F)
void Emulator::instr_JG_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    bool zf = (regs.EFLAGS & ZF) != 0;
    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;
    if (!zf && (sf == of)) {
        regs.EIP += rel32;
    }
}
void Emulator::instr_MOV_rm8_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm & 0xC0) >> 6;
    // uint8_t reg = (modrm & 0x38) >> 3; // Не используется для MOV r/m8, imm8
    uint8_t rm = (modrm & 0x07);       // Назначение: r/m8

    uint8_t imm8 = fetch_byte();

    if (mod == 3) { // Регистр
        uint32_t* dest_reg = get_register_by_code(rm);
        if (dest_reg) {
            // Только младший байт регистра
            uint8_t* dest_reg_byte = reinterpret_cast<uint8_t*>(dest_reg);
            dest_reg_byte[0] = imm8;
        }
        else {
            std::cout << "Неизвестный регистр в MOV r/m8, imm8.\n";
            error_flag = true;
            running = false;
        }
    }
    else { // Память
        uint32_t address = calculate_address(modrm);
        if (error_flag) {
            return; // Ошибка уже установлена в calculate_address
        }

        if (address >= memory.size()) {
            std::cout << "Memory access out of bounds in MOV r/m8, imm8.\n";
            error_flag = true;
            running = false;
            return;
        }

        memory[address] = imm8;
    }
}

// Обработчик инструкции MUL r/m32
void Emulator::instr_MUL_rm32(uint8_t modrm) {
    uint8_t mod = (modrm & 0xC0) >> 6;
    // uint8_t reg = (modrm & 0x38) >> 3; // Не используется для MUL r/m32
    uint8_t rm = (modrm & 0x07);       // Источник: r/m32

    uint32_t operand = 0;

    if (mod == 3) { // Регистр
        uint32_t* src_reg = get_register_by_code(rm);
        if (src_reg) {
            operand = *src_reg;
        }
        else {
            std::cout << "Неизвестный регистр в MUL r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand = read_memory_dword(address);
    }

    // Выполнение умножения: EDX:EAX = EAX * operand
    uint64_t result = static_cast<uint64_t>(regs.EAX) * static_cast<uint64_t>(operand);
    regs.EAX = static_cast<uint32_t>(result & 0xFFFFFFFF);
    regs.EDX = static_cast<uint32_t>((result >> 32) & 0xFFFFFFFF);

    update_ZF(regs.EAX);
}

// Реализация обработчика для DIV r/m32
void Emulator::instr_DIV_rm32(uint8_t modrm) {
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;

    uint32_t operand = 0;

    if (mod == 3) { // Регистровый операнд
        uint32_t* src_reg = get_register_by_code(rm);
        if (src_reg) {
            operand = *src_reg;
        }
        else {
            std::cout << "Неизвестный регистр в DIV r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else { // Операнд из памяти
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand = read_memory_dword(address); // Чтение операнда из памяти
    }

    if (operand == 0) {
        std::cout << "Деление на ноль.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Выполнение деления: EDX:EAX = EAX / operand
    uint64_t dividend = (static_cast<uint64_t>(regs.EDX) << 32) | regs.EAX;
    regs.EAX = static_cast<uint32_t>(dividend / operand);
    regs.EDX = static_cast<uint32_t>(dividend % operand);

    //std::cout << "DIV instruction: Dividend = " << dividend << ", Operand = " << operand
        //<< ", EAX = " << regs.EAX << ", EDX = " << regs.EDX << "\n";

    update_ZF(regs.EAX);
}
void Emulator::instr_LEA_r32_m() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg = (modrm >> 3) & 0x07; // Destination register code
    uint8_t rm = modrm & 0x07;         // Source operand

    // LEA is invalid with mod == 3 (register-direct mode)
    if (mod == 3) {
        std::cout << "Invalid LEA instruction with mod == 3.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Calculate the effective address
    uint32_t address = calculate_address(modrm);
    if (error_flag)
        return;

    // Get the destination register
    uint32_t* dest_reg = get_register_by_code(reg);
    if (!dest_reg) {
        std::cout << "Unknown destination register in LEA.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Store the effective address into the destination register
    *dest_reg = address;
}
void Emulator::instr_IDIV_rm32(uint8_t modrm) {
    uint8_t mod = (modrm & 0xC0) >> 6;
    uint8_t rm = (modrm & 0x07);       // Источник: r/m32

    int32_t operand = 0;

    if (mod == 3) { // Регистр
        int32_t* src_reg = reinterpret_cast<int32_t*>(get_register_by_code(rm));
        if (src_reg) {
            operand = *src_reg;
        }
        else {
            std::cout << "Неизвестный регистр в IDIV r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else { // Операнд из памяти
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand = read_memory_dword(address); // Чтение операнда из памяти
    }

    if (operand == 0) {
        std::cout << "Деление на ноль.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Выполнение деления: EDX:EAX = EAX / operand
    int64_t dividend = (static_cast<int64_t>(regs.EDX) << 32) | regs.EAX;
    regs.EAX = static_cast<uint32_t>(dividend / operand);
    regs.EDX = static_cast<uint32_t>(dividend % operand);

    update_ZF(regs.EAX);
}

// Общий обработчик для opcode 0xF7
void Emulator::instr_F7() {
    uint8_t modrm = fetch_byte();
    uint8_t reg = (modrm >> 3) & 0x07; // /digit

    switch (reg) {
    case 4: // MUL r/m32
        instr_MUL_rm32(modrm);
        break;
    case 6: // DIV r/m32
        instr_DIV_rm32(modrm);
        break;
    case 7: // IDIV r/m32
        instr_IDIV_rm32(modrm);
        break;
    default:
        std::cout << "F7 instruction with unsupported /digit: " << static_cast<int>(reg) << "\n";
        error_flag = true;
        running = false;
        break;
    }
}

void Emulator::instr_MOV_rm8_r8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;
    uint8_t reg = (modrm >> 3) & 0x07;

    uint8_t* src_reg = get_register8_by_code(reg);
    if (!src_reg) {
        std::cout << "Unknown source register in MOV r/m8, r8.\n";
        error_flag = true;
        running = false;
        return;
    }
    uint8_t value = *src_reg;

    if (mod == 3) {
        // Режим регистр-регистр
        uint8_t* dest_reg = get_register8_by_code(rm);
        if (!dest_reg) {
            std::cout << "Unknown destination register in MOV r/m8, r8.\n";
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg = value;
    }

    else {
        // Режим регистр-память
        uint32_t address = 0;
        if (rm == 4) {
            // SIB байт
            uint8_t sib = fetch_byte();
            int32_t displacement = 0;
            if (mod == 1) {
                displacement = static_cast<int8_t>(fetch_byte());
            }
            else if (mod == 2) {
                displacement = static_cast<int32_t>(fetch_dword());
            }
            address = calculate_sib_address(mod, sib, displacement);
        }
        else {
            int32_t displacement = 0;
            if (mod == 1) {
                displacement = static_cast<int8_t>(fetch_byte());
            }
            else if (mod == 2) {
                displacement = static_cast<int32_t>(fetch_dword());
            }
            address = *get_register_by_code(rm) + displacement;
        }
        if (address >= memory.size()) {
            std::cout << "Memory access out of bounds in MOV r/m8, r8.\n";
            error_flag = true;
            running = false;
            return;
        }
        memory[address] = value;
    }
    
}

void Emulator::instr_ADD_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    *al += imm8;
    update_ZF(*al); // Обновляем флаг ZF на основе 8-битного результата
}

void Emulator::instr_MOV_ESI_imm32() {
    regs.ESI = fetch_dword();
}

// INT n (0xCD)
void Emulator::instr_INT() {
    uint8_t int_number = fetch_byte();
    if (int_number == 0x80) {
        // Обработка системного вызова Linux
        uint32_t syscall_number = regs.EAX;
        switch (syscall_number) {
        case 3: { // sys_read
            uint32_t fd = regs.EBX;
            uint32_t buf = regs.ECX;
            uint32_t count = regs.EDX;

            if (fd == 0) { // stdin
                std::string input;
                std::getline(std::cin, input);

                // Читаем не более count байтов
                input = input.substr(0, count);

                // Записываем введённые данные в память
                for (size_t i = 0; i < input.size(); ++i) {
                    memory[buf + i] = static_cast<uint8_t>(input[i]);
                }

                // Если введённых данных меньше, чем запрошено, заполняем оставшиеся нулями
                for (size_t i = input.size(); i < count; ++i) {
                    memory[buf + i] = 0;
                }

                // Возвращаем количество прочитанных байтов в EAX
                regs.EAX = input.size();
            }
            else {
                std::cout << "Unsupported file descriptor in sys_read: " << fd << "\n";
                regs.EAX = -1; // Возвращаем -1 в случае ошибки
            }
            break;
        }
        case 4: { // sys_write
            uint32_t fd = regs.EBX;
            uint32_t buf = regs.ECX;
            uint32_t count = regs.EDX;
            if (fd == 1) { // stdout
                std::string output;
                for (uint32_t i = 0; i < count; ++i) {
                    output += static_cast<char>(memory[buf + i]);
                }
                std::cout << output; // Вывод строки
            }
            break;
        }
        case 1: { // sys_exit
            running = false;
            break;
        }
        default:
            std::cout << "Неизвестный системный вызов: " << syscall_number << "\n";
            running = false;
            break;
        }
    }
    else {
        std::cout << "Неизвестное прерывание: INT " << (int)int_number << "\n";
        running = false;
    }
}

void Emulator::instr_MOV_MEM_EAX() {
    uint32_t address = fetch_dword();
    if (address + 4 > memory.size()) {
        throw std::runtime_error("Выход за пределы памяти при MOV [address], EAX");
    }
    memory[address] = regs.EAX & 0xFF;
    memory[address + 1] = (regs.EAX >> 8) & 0xFF;
    memory[address + 2] = (regs.EAX >> 16) & 0xFF;
    memory[address + 3] = (regs.EAX >> 24) & 0xFF;
}

void Emulator::instr_MOV_EAX_MEM() {
    uint32_t address = fetch_dword();
    if (address + 4 > memory.size()) {
        throw std::runtime_error("Выход за пределы памяти при MOV EAX, [address]");
    }
    regs.EAX = memory[address] |
        (memory[address + 1] << 8) |
        (memory[address + 2] << 16) |
        (memory[address + 3] << 24);
}
// CMP EAX, EBX
void Emulator::instr_CMP_EAX_EBX() {
    uint8_t modrm = fetch_byte(); // Получаем ModRM байт
    uint8_t reg = (modrm >> 3) & 0x07; // Извлекаем регистры
    uint8_t rm = modrm & 0x07;

    // Проверяем, что регистры соответствуют EAX и EBX
    if (reg == 0 && rm == 3) { // 0 для EAX и 3 для EBX
        uint32_t result = regs.EAX - regs.EBX;

        // Zero Flag (ZF)
        if (result == 0)
            regs.EFLAGS |= ZF;
        else
            regs.EFLAGS &= ~ZF;

        // Sign Flag (SF)
        if (result & (1 << 31))
            regs.EFLAGS |= SF;
        else
            regs.EFLAGS &= ~SF;

        // Остальная обработка флагов
    }
    else {
        std::cout << "CMP instruction with unsupported register combination.\n";
        error_flag = true;
        running = false;
    }
}

void Emulator::instr_JG_rel8() {
    int8_t rel = fetch_byte();

    bool zf = (regs.EFLAGS & ZF) != 0;
    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;

    // JG переходит, если ZF = 0 и SF = OF
    if (!zf && (sf == of)) {
        regs.EIP += rel;
    }
}
// Реализация инструкции IMUL reg, r/m32, imm32
void Emulator::instr_IMUL_reg_rm32_imm32() {
    // Before reading ModRM byte, EIP points to it
    std::cout << "EIP before fetch_byte (ModRM): 0x" << std::hex << regs.EIP << "\n";

    uint8_t modrm = fetch_byte(); // Read ModRM byte
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Destination register
    uint8_t rm_code = modrm & 0x07;         // Source operand

    // Debug output
    std::cout << "Executing IMUL with modrm: 0x" << std::hex << (int)modrm << "\n";
    std::cout << "Destination reg code: " << (int)reg_code << ", Source rm code: " << (int)rm_code << "\n";
    std::cout << "EIP after fetch_byte (ModRM): 0x" << std::hex << regs.EIP << "\n";

    uint32_t* dest_reg = get_register_by_code(reg_code);
    uint32_t* src_reg = nullptr;

    if (mod == 3) { // Register-register mode
        src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            std::cout << "Unknown source register in IMUL.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        std::cout << "Unsupported addressing mode in IMUL.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Check if dest_reg is valid
    if (!dest_reg) {
        std::cout << "Unknown destination register in IMUL.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Before reading imm32, EIP points to it
    std::cout << "EIP before fetch_dword (imm32): 0x" << std::hex << regs.EIP << "\n";

    uint32_t imm32 = fetch_dword(); // Read immediate value imm32

    // After reading imm32, EIP should have been incremented by 4
    std::cout << "EIP after fetch_dword (imm32): 0x" << std::hex << regs.EIP << "\n";
    // Debug output of imm32
    std::cout << "Immediate value: " << std::dec << imm32 << "\n";

    // Perform signed multiplication
    int32_t result = static_cast<int32_t>(*src_reg) * static_cast<int32_t>(imm32);
    *dest_reg = static_cast<uint32_t>(result);

    // Update flags appropriately
    update_ZF(*dest_reg);
    // Update other flags (CF, OF) if necessary
}

void Emulator::instr_SUB_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    *al -= imm8;
    update_ZF(*al);
}
void Emulator::instr_JMP_rel8() {
    int8_t rel = fetch_byte();
    regs.EIP += rel;
}
void Emulator::instr_JB_rel8() {
    int8_t rel = fetch_byte();
    if (regs.EFLAGS & CF) {
        regs.EIP += rel;
    }
}

void Emulator::instr_JA_rel8() {
    int8_t rel = fetch_byte();
    bool cf = (regs.EFLAGS & CF) != 0;
    bool zf = (regs.EFLAGS & ZF) != 0;
    if (!cf && !zf) {
        regs.EIP += rel;
    }
}
void Emulator::instr_INC_ECX() {
    regs.ECX += 1;
    update_ZF(regs.ECX);
}
void Emulator::instr_MOV_r8_imm8() {
    uint8_t opcode = memory[regs.EIP - 1]; // Последний прочитанный опкод
    uint8_t reg_code = opcode - 0xB0; // Регистры AL, CL, DL, BL, AH, CH, DH, BH идут от 0xB0 до 0xB7

    uint8_t imm8 = fetch_byte();
    uint8_t* reg = get_register8_by_code(reg_code);

    if (!reg) {
        std::cout << "Unknown register in MOV r8, imm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    *reg = imm8;
}
void Emulator::instr_SUB_rm8_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t opcode = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;

    if (opcode != 5) {
        std::cout << "Unsupported opcode in SUB rm8, imm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    uint8_t imm8 = fetch_byte();
    uint8_t* dest = get_register8_by_code(rm_code);

    if (!dest) {
        std::cout << "Unknown register in SUB rm8, imm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    *dest -= imm8;

    update_ZF(*dest);
}
void Emulator::instr_MOV_r8_rm8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Назначение: r8
    uint8_t rm = modrm & 0x07;              // Источник: r/m8

    uint8_t* reg = get_register8_by_code(reg_code);
    if (!reg) {
        std::cout << "Unknown register in MOV r8, rm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    uint32_t address = 0;

    if (mod == 0) {
        if (rm == 4) {
            // Обработка SIB байта
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, 0);
        }
        else if (rm == 5) {
            // [disp32]
            address = fetch_dword();
        }
        else {
            // [reg]
            uint32_t* rm_reg = get_register_by_code(rm);
            if (rm_reg) {
                address = *rm_reg;
            }
            else {
                std::cout << "Unknown base register in MOV r8, rm8.\n";
                error_flag = true;
                running = false;
                return;
            }
        }
    }
    else if (mod == 1) {
        int8_t disp8 = static_cast<int8_t>(fetch_byte());
        if (rm == 4) {
            // Обработка SIB байта
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp8);
        }
        else {
            // [reg + disp8]
            uint32_t* rm_reg = get_register_by_code(rm);
            if (rm_reg) {
                address = *rm_reg + disp8;
            }
            else {
                std::cout << "Unknown base register in MOV r8, rm8.\n";
                error_flag = true;
                running = false;
                return;
            }
        }
    }
    else if (mod == 2) {
        int32_t disp32 = static_cast<int32_t>(fetch_dword());
        if (rm == 4) {
            // Обработка SIB байта
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp32);
        }
        else {
            // [reg + disp32]
            uint32_t* rm_reg = get_register_by_code(rm);
            if (rm_reg) {
                address = *rm_reg + disp32;
            }
            else {
                std::cout << "Unknown base register in MOV r8, rm8.\n";
                error_flag = true;
                running = false;
                return;
            }
        }
    }
    else if (mod == 3) {
        // MOV r8, r8
        uint8_t* rm_reg = get_register8_by_code(rm);
        if (rm_reg) {
            *reg = *rm_reg;
        }
        else {
            std::cout << "Unknown register in MOV r8, rm8.\n";
            error_flag = true;
            running = false;
        }
        return;
    }
    else {
        std::cout << "Unsupported mod in MOV r8, rm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    if (address >= memory.size()) {
        std::cout << "Memory access out of bounds in MOV r8, [address].\n";
        error_flag = true;
        running = false;
        return;
    }

    *reg = memory[address];
}
// MOV EBP, imm32
void Emulator::instr_MOV_EBP_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBP = imm;
}
// MOV ESP, imm32
void Emulator::instr_MOV_ESP_imm32() {
    uint32_t imm = fetch_dword();
    regs.ESP = imm;
}

// MOV EDI, imm32
void Emulator::instr_MOV_EDI_imm32() {
    uint32_t imm = fetch_dword();
    regs.EDI = imm;
}
void Emulator::instr_MOV_r32_r_m32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07; // Destination register (r32)
    uint8_t rm = modrm & 0x07;         // Source (r/m32)

    uint32_t* dest_reg = get_register_by_code(reg);

    if (mod == 3) { // Register-register mode
        uint32_t* src_reg = get_register_by_code(rm);
        if (dest_reg && src_reg) {
            *dest_reg = *src_reg;
        }
        else {
            std::cout << "Unknown register in MOV r32, r/m32.\n";
            error_flag = true;
            running = false;
        }
    }
    else { // Memory to register
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;

        uint32_t value = read_memory_dword(address);
        if (dest_reg) {
            *dest_reg = value;
        }
        else {
            std::cout << "Unknown destination register in MOV r32, r/m32.\n";
            error_flag = true;
            running = false;
        }
    }
}
void Emulator::instr_ADD_r32_rm32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm); // Предполагается, что вы реализовали структуру Operand

    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;

    uint32_t* reg = get_register_by_code(reg_code);

    if (!reg) {
        std::cout << "Unknown destination register in ADD r32, r/m32.\n";
        error_flag = true;
        running = false;
        return;
    }

    if (operand.is_memory) {
        uint32_t value = read_memory_dword(operand.address);
        *reg += value;
    }
    else {
        uint32_t* src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            std::cout << "Unknown source register in ADD r32, r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
        *reg += *src_reg;
    }

    update_ZF(*reg);
    // Обновите другие флаги при необходимости
}

void Emulator::instr_ADD_rm32_r32() {
    bool is_locked = regs.lock_prefix;

    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Source register (r32)
    uint8_t rm_code = modrm & 0x07;         // Destination (r/m32)

    uint32_t* src_reg = get_register_by_code(reg_code);

    if (mod == 3) { // Register-register mode
        uint32_t* dest_reg = get_register_by_code(rm_code);
        if (src_reg && dest_reg) {
            if (is_locked) {
                std::cout << "LOCK prefix applied to ADD r32, r/m32.\n";
            }
            *dest_reg += *src_reg;
            update_ZF(*dest_reg);
            // Update other flags as needed
        }
        else {
            std::cout << "Unknown register in ADD r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    else { // Memory operand
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;

        uint32_t value = read_memory_dword(address);
        value += *src_reg;
        write_memory_dword(address, value);
        update_ZF(value);
        // Update other flags as needed
    }
    reset_prefixes();
}
void Emulator::instr_CMP_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t al = regs.EAX & 0xFF;
    uint8_t result = al - imm8;

    // Update Zero Flag (ZF)
    if (result == 0)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;

    // Update Sign Flag (SF)
    if (result & 0x80)
        regs.EFLAGS |= SF;
    else
        regs.EFLAGS &= ~SF;

    // Update Carry Flag (CF)
    if (al < imm8)
        regs.EFLAGS |= CF;
    else
        regs.EFLAGS &= ~CF;

    // Update Overflow Flag (OF)
    bool overflow = ((al ^ imm8) & (al ^ result) & 0x80) != 0;
    if (overflow)
        regs.EFLAGS |= OF;
    else
        regs.EFLAGS &= ~OF;
}
void Emulator::instr_JL_rel8() {
    int8_t rel = fetch_byte();

    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;

    // JL переходит, если SF != OF
    if (sf != of) {
        regs.EIP += rel;
    }
}

void Emulator::instr_XOR_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07; // Source register (r32)
    uint8_t rm = modrm & 0x07;         // Destination (r/m32)

    if (mod == 3) { // Register-register mode
        uint32_t* src_reg = get_register_by_code(reg);
        uint32_t* dest_reg = get_register_by_code(rm);

        if (src_reg && dest_reg) {
            *dest_reg ^= *src_reg;
            update_ZF(*dest_reg);
        }
        else {
            std::cout << "Unknown register in XOR r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    // ...
}
void Emulator::instr_CALL_rel32() {
    // Fetch the relative 32-bit offset
    int32_t rel32 = fetch_dword();

    // Calculate the return address (current EIP)
    uint32_t return_address = regs.EIP;

    // Push the return address onto the stack
    regs.ESP -= 4;
    write_memory_dword(regs.ESP, return_address);

    // Update EIP to jump to the target address
    regs.EIP += rel32;
}
// Обработчик для opcode 0x81 (32-битное непосредственное значение)
void Emulator::instr_GROUP1_Ev_Iz_81() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_opcode = (modrm >> 3) & 0x07; // Поле reg в ModRM
    uint8_t rm = modrm & 0x07;

    uint32_t* dest_reg = nullptr;
    if (mod == 3) { // Режим регистр-регистр
        dest_reg = get_register_by_code(rm);
    }
    else {
        // Обработка памяти (не реализовано)
        std::cout << "Memory operands not implemented for opcode 0x81.\n";
        error_flag = true;
        running = false;
        return;
    }

    uint32_t imm32 = fetch_dword(); // Чтение 32-битного непосредственного значения

    switch (reg_opcode) {
    case 0: // ADD
        *dest_reg += imm32;
        update_ZF(*dest_reg);
        break;
    case 1: // OR
        *dest_reg |= imm32;
        update_ZF(*dest_reg);
        break;
    case 2: // ADC
        // Реализуйте ADC при необходимости
        break;
    case 3: // SBB
        // Реализуйте SBB при необходимости
        break;
    case 4: // AND
        *dest_reg &= imm32;
        update_ZF(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= imm32;
        update_ZF(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= imm32;
        update_ZF(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - imm32;
        update_ZF(result);
        // Обновите другие флаги при необходимости
    }
    break;
    default:
        std::cout << "Unsupported reg opcode in opcode 0x81: " << (int)reg_opcode << "\n";
        error_flag = true;
        running = false;
        break;
    }
}

// Обработчик для opcode 0x83 (8-битное непосредственное значение)
void Emulator::instr_GROUP1_Ev_Iz_83() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_opcode = (modrm >> 3) & 0x07; // Поле reg в ModRM
    uint8_t rm = modrm & 0x07;

    uint32_t* dest_reg = nullptr;
    if (mod == 3) { // Режим регистр-регистр
        dest_reg = get_register_by_code(rm);
    }
    else {
        // Обработка памяти (не реализовано)
        std::cout << "Memory operands not implemented for opcode 0x83.\n";
        error_flag = true;
        running = false;
        return;
    }

    int8_t imm8 = static_cast<int8_t>(fetch_byte()); // Чтение 8-битного непосредственного значения

    // Знаковое расширение до 32 бит
    int32_t sign_extended_imm = static_cast<int32_t>(imm8);

    switch (reg_opcode) {
    case 0: // ADD
        *dest_reg += sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 1: // OR
        *dest_reg |= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 2: // ADC
        // Реализуйте ADC при необходимости
        break;
    case 3: // SBB
        // Реализуйте SBB при необходимости
        break;
    case 4: // AND
        *dest_reg &= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - sign_extended_imm;
        update_ZF(result);
        // Обновите другие флаги при необходимости
    }
    break;
    default:
        std::cout << "Unsupported reg opcode in opcode 0x83: " << (int)reg_opcode << "\n";
        error_flag = true;
        running = false;
        break;
    }
}
void Emulator::instr_JL_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;
    if (sf != of) {
        regs.EIP += rel32;
    }
}
void Emulator::instr_MOVSB() {
    // Обработка префиксов REP/REPE/REPNE
    if (regs.rep_prefix || regs.repne_prefix) {
        // Определяем тип префикса
        bool is_rep = regs.rep_prefix;
        bool is_repne = regs.repne_prefix;

        while (regs.ECX != 0) {
            uint8_t byte = read_memory_byte(regs.ESI);
            write_memory_byte(regs.EDI, byte);
            regs.ESI += 1;
            regs.EDI += 1;
            regs.ECX -= 1;

            // Обновление флагов по необходимости
            update_ZF(byte);

            // Для `REPNE` можно добавить условия выхода
            if (is_repne && (regs.EFLAGS & ZF)) {
                break;
            }

            if (is_rep && regs.ECX == 0) {
                break;
            }
        }

        // Сброс префиксов после выполнения
        reset_prefixes();
    }
    else {
        // Обычное выполнение MOVSB без повторения
        uint8_t byte = read_memory_byte(regs.ESI);
        write_memory_byte(regs.EDI, byte);
        regs.ESI += 1;
        regs.EDI += 1;

        // Обновление флагов по необходимости
        update_ZF(byte);
    }
}

void Emulator::instr_MOV_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07; // Source register (r32)
    uint8_t rm = modrm & 0x07;         // Destination (r/m32)

    if (mod == 3) { // Register-register mode
        uint32_t* src_reg = get_register_by_code(reg);
        uint32_t* dest_reg = get_register_by_code(rm);

        if (src_reg && dest_reg) {
            *dest_reg = *src_reg;
        }
        else {
            std::cout << "Unknown register in MOV r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    // ...
}
// main.cpp
#include "Emulator.h"
#include "file_utils.h"
#include "elf_loader.h"
#include <iostream>
#include <vector>
#include <cstdint>
#include <string>

bool run_program_from_file(const std::string& filename) {
    Emulator emulator(1024 * 1024); // 1 MB памяти

    // Загрузка программы из бинарного файла
    std::vector<uint8_t> program = load_program_from_file(filename);
    if (program.empty()) {
        std::cerr << "Ошибка: Не удалось загрузить программу из файла: " << filename << "\n";
        return false;
    }

    // Загрузка программы в память по адресу 0x0000 и установка EIP
    emulator.load_program(program, 0x0000, true);

    // Запуск эмулятора
    emulator.run();

    // Проверка на ошибки
    return !emulator.has_error();
}

bool run_program_from_elf(const std::string& filename) {
    Emulator emulator(256 * 1024 * 1024); // 256 MB памяти

    // Загрузка ELF-файла
    bool load_result = load_elf(filename, emulator);
    if (!load_result) {
        std::cerr << "Ошибка: Не удалось загрузить ELF-файл.\n";
        return false;
    }
    //emulator.print_registers(true);
    // Запуск эмулятора
    emulator.run();

    // Проверка на ошибки
    return !emulator.has_error();
}

int main(int argc, char* argv[]) {
    // Проверка наличия аргумента командной строки
    if (argc > 1) {
        std::string program_filename = argv[1];
        std::cout << "\nЗапуск программы из файла: " << program_filename << "...\n";

        // Определение типа файла по расширению
        if (program_filename.size() >= 4 &&
            program_filename.substr(program_filename.size() - 4) == ".elf") {
            // Запуск как ELF-файл
            bool elf_result = run_program_from_elf(program_filename);

            if (elf_result) {
                std::cout << "\nПрограмма из ELF-файла успешно выполнена!\n";
            }
            else {
                std::cout << "\nПрограмма из ELF-файла не выполнена.\n";
            }
        }
        else {
            // Запуск как flat binary
            bool file_result = run_program_from_file(program_filename);

            if (file_result) {
                std::cout << "\nПрограмма из файла успешно выполнена!\n";
            }
            else {
                std::cout << "\nПрограмма из файла не выполнена.\n";
            }
        }
    }
    else {
        // Если файл не указан, можно запустить тесты или вывести инструкции
        std::cout << "Использование: " << argv[0] << " <имя_файла.(elf|bin)>\n";
    }

    return 0;
}
C:\Users\Swed\source\repos\x86_Emulator\x64\Debug>x86_Emulator.exe main.elf

Запуск программы из файла: main.elf...
Объем выделенной памяти эмулятора: 256 MB
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x0
  p_memsz: 980 байт
  p_filesz: 980 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x1000
  p_memsz: 500 байт
  p_filesz: 500 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x2000
  p_memsz: 252 байт
  p_filesz: 252 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x3ed8
  p_memsz: 308 байт
  p_filesz: 304 байт
ELF-файл успешно загружен. Точка входа: 0x1070
Обнаружен префикс: 0xf3
Выполнена инструкция ENDBR32 (пропущена).
Stack underflow on POP ESI.

Программа из ELF-файла не выполнена.

swed@DESKTOP-K5N5PON:~$ gcc -m32 -nostdlib -nostartfiles -nodefaultlibs -fno-stack-protector -fcf-protection=none -Wl,-T,linker.ld main.c -o main.elf
/* main.c */
__asm__(
    ".global _start     \n"
    "_start:            \n"
    "   call main       \n"
    "   movl %eax, %ebx \n"
    "   movl $1, %eax   \n"  /* sys_exit */
    "   int $0x80       \n"
);

void write(const char* str, unsigned int len) {
    __asm__(
        "movl $4, %%eax   \n"  /* sys_write */
        "movl $1, %%ebx   \n"  /* stdout */
        "int $0x80        \n"
        :
        : "c"(str), "d"(len)
    );
}

void main() {
    const char* msg = "Hello World!\n";
    write(msg, 13);
}