// 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_PUSH_EAX() {
    push(regs.EAX);
}

void Emulator::instr_PUSH_ECX() {
    push(regs.ECX);
}

void Emulator::instr_PUSH_EDX() {
    push(regs.EDX);
}

void Emulator::instr_PUSH_EBX() {
    push(regs.EBX);
}

void Emulator::instr_PUSH_ESP() {
    push(regs.ESP);
}

void Emulator::instr_PUSH_EBP() {
    push(regs.EBP);
}

void Emulator::instr_PUSH_ESI() {
    push(regs.ESI);
}

void Emulator::instr_PUSH_EDI() {
    push(regs.EDI);
}
void Emulator::instr_CLD() {
    // Clear the Direction Flag (DF), which is bit 10 in EFLAGS
    regs.EFLAGS &= ~DF_FLAG;

    // Optionally, print debug information
    std::cout << "Выполнена инструкция CLD (Direction Flag сброшен).\n";
}
void Emulator::instr_PUSH_imm8() {
    int8_t imm8 = static_cast<int8_t>(fetch_byte()); // Получаем 8-битное значение
    push(static_cast<uint32_t>(imm8)); // Преобразуем в 32-битное знаковое значение и помещаем в стек
}
void Emulator::push(uint32_t value) {
    if (regs.ESP < 4) {
        std::cerr << "Stack overflow при попытке записать в стек.\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.ESP -= 4;  // Уменьшаем указатель стека
    write_memory_dword(regs.ESP, value);  // Записываем значение в стек
}
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_ESP() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP ESP.\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.ESP = read_memory_dword(regs.ESP);
    regs.ESP += 4;
}
void Emulator::instr_POP_EBX() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP EBX.\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.EBX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
}
void Emulator::instr_POP_EDX() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP EDX.\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.EDX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
}
void Emulator::instr_POP_ECX() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP ECX.\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.ECX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
}
void Emulator::instr_POP_EAX() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP EAX.\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.EAX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
}
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_POP_EDI() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP EDI.\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.EDI = read_memory_dword(regs.ESP);
    regs.ESP += 4;
}
void Emulator::instr_MOV_Ev_Iv() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);

    uint32_t immediate = fetch_dword();

    if (operand.is_memory) {
        write_memory_dword(operand.address, immediate);
    } else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            std::cout << "Unknown register in MOV Ev, Iv.\n";
            error_flag = true;
            running = false;
            return;
        }
        *reg = immediate;
    }
}
// Реализация инструкции INC r/m32
void Emulator::instr_INC_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    if (operand.is_memory) {
        uint32_t value = read_memory_dword(operand.address);
        value++;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        (*reg)++;
    }
    update_ZF_FLAG(operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code));
}

// Реализация инструкции DEC r/m32
void Emulator::instr_DEC_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    if (operand.is_memory) {
        uint32_t value = read_memory_dword(operand.address);
        value--;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        (*reg)--;
    }
    update_ZF_FLAG(operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code));
}
void Emulator::instr_LEAVE() {
    // Set ESP to EBP
    regs.ESP = regs.EBP;

    // POP EBP
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on LEAVE.\n";
        error_flag = true;
        running = false;
        return;
    }

    regs.EBP = read_memory_dword(regs.ESP);
    regs.ESP += 4;

    std::cout << "Выполнена инструкция LEAVE. ESP: 0x" << std::hex << regs.ESP
        << ", EBP: 0x" << regs.EBP << "\n";
}
// Реализация инструкции CALL r/m32
void Emulator::instr_CALL_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t address = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);

    // Сохраняем текущий адрес возврата в стек
    push(regs.EIP);

    // Переходим к новому адресу
    regs.EIP = address;
}

// Реализация инструкции JMP r/m32
void Emulator::instr_JMP_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t address = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
    regs.EIP = address;
}

// Реализация инструкции PUSH r/m32
void Emulator::instr_PUSH_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t value = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
    push(value);
}
void Emulator::instr_PUSH_imm32() {
    uint32_t imm32 = fetch_dword();  // Чтение 32-битного непосредственного значения
    push(imm32);  // Помещение значения в стек
}
void Emulator::instr_GROUP5() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07;  // Поле reg в ModR/M указывает на операцию
    uint8_t rm = modrm & 0x07;

    switch (reg) {
    case 0: // INC r/m32
        instr_INC_rm32(modrm);
        break;
    case 1: // DEC r/m32
        instr_DEC_rm32(modrm);
        break;
    case 2: // CALL r/m32
        instr_CALL_rm32(modrm);
        break;
    case 3: // CALL far
        std::cout << "CALL far не поддерживается.\n";
        error_flag = true;
        running = false;
        break;
    case 4: // JMP r/m32
        instr_JMP_rm32(modrm);
        break;
    case 5: // JMP far
        std::cout << "JMP far не поддерживается.\n";
        error_flag = true;
        running = false;
        break;
    case 6: // PUSH r/m32
        instr_PUSH_rm32(modrm);
        break;
    case 7: // NOT r/m32
        instr_NOT_rm32(modrm);
        break;
    default:
        std::cout << "Неизвестный подтип команды 0xFF: " << (int)reg << "\n";
        error_flag = true;
        running = false;
        break;
    }
}
void Emulator::instr_TEST_rm32_r32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07; // Второй операнд (r32)
    uint8_t rm = modrm & 0x07;         // Первый операнд (r/m32)

    uint32_t operand1 = 0;
    uint32_t operand2 = 0;

    // Получаем второй операнд из регистра
    uint32_t* reg_operand2 = get_register_by_code(reg);
    if (!reg_operand2) {
        std::cout << "Unknown register in TEST r/m32, r32.\n";
        error_flag = true;
        running = false;
        return;
    }
    operand2 = *reg_operand2;

    if (mod == 3) {
        // Режим регистр-регистр
        uint32_t* reg_operand1 = get_register_by_code(rm);
        if (!reg_operand1) {
            std::cout << "Unknown register in TEST r/m32, r32.\n";
            error_flag = true;
            running = false;
            return;
        }
        operand1 = *reg_operand1;
    }
    else {
        // Операнд из памяти
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand1 = read_memory_dword(address);
    }

    // Выполняем побитовое И без сохранения результата
    uint32_t result = operand1 & operand2;

    // Обновляем флаги
    // Флаги CF_FLAG и OF_FLAG сбрасываются
    regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);

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

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

    // Parity Flag (PF)
    update_PF(static_cast<uint8_t>(result & 0xFF));

    // Флаг Auxiliary Carry (AF) не определен для инструкции TEST и может быть оставлен без изменений

    std::cout << "Выполнена инструкция TEST r/m32, r32.\n";
}
void Emulator::instr_ENDBR32() {
    // ENDBR32 is 4 bytes: F3 0F 1E FB
    // We have already processed F3 (prefix) and 0F (escape opcode)
    // 1E has been fetched and identified as opcode for ENDBR32
    // Now, we need to fetch the last byte, which should be 0xFB
    uint8_t last_byte = fetch_byte();
    if (last_byte != 0xFB) {
        std::cout << "Expected byte 0xFB not found after opcode 0x1E for ENDBR32, found: 0x"
            << std::hex << (int)last_byte << ".\n";
        error_flag = true;
        running = false;
        return;
    }
    // ENDBR32 correctly recognized; treat as NOP
    std::cout << "ENDBR32 instruction executed (treated as NOP).\n";
}
void Emulator::instr_STD() {
    // Set the Direction Flag (DF), which is bit 10 in EFLAGS
    regs.EFLAGS |= DF_FLAG;
    std::cout << "Выполнена инструкция STD (Direction Flag установлен).\n";
}
void Emulator::instr_NOP() {
    // NOP does nothing
    std::cout << "Выполнена инструкция NOP.\n";
}
void Emulator::instr_PUSHAD() {
    uint32_t temp_esp = regs.ESP;
    push(regs.EAX);
    push(regs.ECX);
    push(regs.EDX);
    push(regs.EBX);
    push(temp_esp);     // Original value OF_FLAG ESP
    push(regs.EBP);
    push(regs.ESI);
    push(regs.EDI);
    std::cout << "Выполнена инструкция PUSHAD.\n";
}
void Emulator::instr_REP_MOVSB() {
    while (regs.ECX != 0) {
        uint8_t byte = read_memory_byte(regs.ESI);
        write_memory_byte(regs.EDI, byte);

        // Update ESI and EDI based on the Direction Flag
        if (regs.EFLAGS & DF_FLAG) {
            regs.ESI -= 1;
            regs.EDI -= 1;
        }
        else {
            regs.ESI += 1;
            regs.EDI += 1;
        }

        regs.ECX -= 1;
    }
    std::cout << "Выполнена инструкция REP MOVSB.\n";
}
void Emulator::instr_NOT_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);

    if (operand.is_memory) {
        uint32_t value = read_memory_dword(operand.address);
        value = ~value;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            std::cout << "Unknown register in NOT r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
        *reg = ~(*reg);
    }
    // Инструкция NOT не изменяет флаги
    std::cout << "Выполнена инструкция NOT r/m32.\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_FLAG(regs.EAX);
}



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

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

// DEC EAX
void Emulator::instr_DEC_EAX() {
    regs.EAX -= 1;
    update_ZF_FLAG(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_FLAG(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_FLAG;
        else
            regs.EFLAGS &= ~ZF_FLAG;

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

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

        // Overflow Flag (OF_FLAG) - необходимо корректно реализовать
        // Здесь может быть упрощение, для точной реализации требуется дополнительная логика
    }
    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_FLAG) {
        regs.EIP += rel;
    }
}

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

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

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

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

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

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

// SUB EBX, imm32
void Emulator::instr_SUB_EBX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBX -= imm;
    update_ZF_FLAG(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_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
    // Дополнительно можно установить другие флаги (CF_FLAG, OF_FLAG и т.д.)
}

// Обработчик инструкции 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_FLAG(*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_FLAG)
    if (result == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;

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

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

    // Overflow Flag (OF_FLAG)
    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_FLAG;
    else
        regs.EFLAGS &= ~OF_FLAG;
}
// Обработчик инструкции JE rel32 (0x0F 0x84)
void Emulator::instr_JE_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    if (regs.EFLAGS & ZF_FLAG) { // Проверка флага равенства
        regs.EIP += rel32;
    }
}

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

// Обработчик инструкции JG rel32 (0x0F 0x8F)
void Emulator::instr_JG_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    bool ZF_FLAG = (regs.EFLAGS & ZF_FLAG) != 0;
    bool SF_FLAG = (regs.EFLAGS & SF_FLAG) != 0;
    bool OF_FLAG = (regs.EFLAGS & OF_FLAG) != 0;
    if (!ZF_FLAG && (SF_FLAG == OF_FLAG)) {
        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_FLAG 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_FLAG(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_FLAG(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_FLAG(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_FLAG 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_FLAG(*al); // Обновляем флаг ZF_FLAG на основе 8-битного результата
}
void Emulator::instr_POP_EBP() {
    if (regs.ESP + 4 > memory.size()) {
        std::cerr << "Stack underflow on POP EBP.\n";
        error_flag = true;
        running = false;
        return;
    }
    // Pop the value from the stack into EBP
    regs.EBP = read_memory_dword(regs.ESP);
    regs.ESP += 4;

    std::cout << "Выполнен POP EBP. Значение в регистре EBP: 0x" << std::hex << regs.EBP << "\n";
}
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 1: // sys_exit
            running = false;
            break;
        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 в случае ошибки
            }
        }
        case 4: { // sys_write
            uint32_t fd = regs.EBX;
            uint32_t buf = regs.ECX;
            uint32_t count = regs.EDX;
            // Debug output
            std::cout << "sys_write called with fd=" << fd
                << ", buf=0x" << std::hex << buf
                << ", count=" << std::dec << count << "\n";
            if (fd == 1) { // stdout
                // Ensure the buffer address is within memory bounds
                if (buf + count > memory.size()) {
                    std::cout << "Buffer out OF_FLAG bounds in sys_write.\n";
                    regs.EAX = -1; // Return -1 on error
                    break;
                }
                std::string output;
                for (uint32_t i = 0; i < count; ++i) {
                    output += static_cast<char>(memory[buf + i]);
                }
                std::cout << output; // Output the string

                // Return the number OF_FLAG bytes written
                regs.EAX = count;
            }

            else {
                std::cout << "Unsupported file descriptor in sys_write: " << fd << "\n";
                regs.EAX = -1; // Return -1 on error
            }
            break;
        }
        case 45: { // sys_brk
            uint32_t addr = regs.EBX;
            if (addr == 0) {
                // Возвращаем текущий адрес brk
                regs.EAX = current_brk;
            }
            else {
                // Устанавливаем новый адрес brk
                if (addr >= data_segment_start && addr < memory.size()) {
                    current_brk = addr;
                    regs.EAX = current_brk;
                }
                else {
                    // Ошибка: попытка установить brk за пределами памяти
                    regs.EAX = 0; // Ошибка
                }
            }
            break;
        }
        case 90: // sys_mmap
            // Реализация sys_mmap
            break;
        case 91: { // sys_munmap
            uint32_t addr = regs.EBX;
            uint32_t length = regs.ECX;
            // Для простоты, можно игнорировать освобождение памяти
            regs.EAX = 0;
            break;
        }
        case 5: { // sys_open
            const char* filename = reinterpret_cast<const char*>(&memory[regs.EBX]); // Путь к файлу
            uint32_t flags = regs.ECX;
            uint32_t mode = regs.EDX;
            // Для простоты, возвращаем фиктивный файловый дескриптор, например 3
            regs.EAX = 3;
            break;
        }
        case 6: { // sys_close
            uint32_t fd = regs.EBX;
            // Ничего не делаем, возвращаем успех
            regs.EAX = 0;
            break;
        }
        case 192: { // sys_mmap2
            uint32_t addr = regs.EBX;
            uint32_t length = regs.ECX;
            uint32_t prot = regs.EDX;
            uint32_t flags = regs.ESI;
            uint32_t fd = regs.EDI;
            uint32_t pgOF_FLAGfset = regs.EBP;

            // Если addr равен 0, выбираем свободный адрес
            if (addr == 0) {
                addr = allocate_memory(0, length);
            }
            else {
                // Проверяем, можем ли мы выделить память по запрошенному адресу
                addr = allocate_memory(addr, length);
            }

            if (addr == 0) {
                // Ошибка при выделении памяти
                regs.EAX = -1;
            }
            else {
                // Успешное выделение памяти
                regs.EAX = addr;
            }
            break;
        }
        case 195: // sys_fstat
            // Реализация sys_fstat
            break;
        case 197: { // sys_fstat64
            uint32_t fd = regs.EBX;
            uint32_t buf = regs.ECX;
            // Возвращаем фиктивные данные
            // В структуре struct stat64 около 104 байт
            memset(&memory[buf], 0, 104);
            regs.EAX = 0;
            break;
        }
        default:
            std::cout << "Неизвестный системный вызов: " << syscall_number << "\n";
            running = false;
            break;
        }
    }
    else {
        std::cout << "Неизвестное прерывание: INT " << (int)int_number << "\n";
        error_flag = true;
        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_FLAG)
        if (result == 0)
            regs.EFLAGS |= ZF_FLAG;
        else
            regs.EFLAGS &= ~ZF_FLAG;

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

        // Остальная обработка флагов
    }
    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_FLAG = (regs.EFLAGS & ZF_FLAG) != 0;
    bool SF_FLAG = (regs.EFLAGS & SF_FLAG) != 0;
    bool OF_FLAG = (regs.EFLAGS & OF_FLAG) != 0;

    // JG переходит, если ZF_FLAG = 0 и SF_FLAG = OF_FLAG
    if (!ZF_FLAG && (SF_FLAG == OF_FLAG)) {
        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_FLAG 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_FLAG(*dest_reg);
    // Update other flags (CF_FLAG, OF_FLAG) 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_FLAG(*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_FLAG) {
        regs.EIP += rel;
    }
}

void Emulator::instr_JA_rel8() {
    int8_t rel = fetch_byte();
    bool CF_FLAG = (regs.EFLAGS & CF_FLAG) != 0;
    bool ZF_FLAG = (regs.EFLAGS & ZF_FLAG) != 0;
    if (!CF_FLAG && !ZF_FLAG) {
        regs.EIP += rel;
    }
}
void Emulator::instr_INC_ECX() {
    regs.ECX += 1;
    update_ZF_FLAG(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_FLAG(*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_FLAG 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_FLAG(*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_FLAG(*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_FLAG(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_FLAG)
    if (result == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;

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

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

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

    bool SF_FLAG = (regs.EFLAGS & SF_FLAG) != 0;
    bool OF_FLAG = (regs.EFLAGS & OF_FLAG) != 0;

    // JL переходит, если SF_FLAG != OF_FLAG
    if (SF_FLAG != OF_FLAG) {
        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_FLAG(*dest_reg);
        }
        else {
            std::cout << "Unknown register in XOR r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    // ...
}
void Emulator::instr_CALL_rel32() {
    int32_t rel32 = fetch_dword();
    // Push the next instruction address onto the stack
    push(regs.EIP);
    // 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_FLAG(*dest_reg);
        break;
    case 1: // OR
        *dest_reg |= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 2: // ADC
        // Реализуйте ADC при необходимости
        break;
    case 3: // SBB
        // Реализуйте SBB при необходимости
        break;
    case 4: // AND
        *dest_reg &= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - imm32;
        update_ZF_FLAG(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_FLAG(*dest_reg);
        break;
    case 1: // OR
        *dest_reg |= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 2: // ADC
        // Реализуйте ADC при необходимости
        break;
    case 3: // SBB
        // Реализуйте SBB при необходимости
        break;
    case 4: // AND
        *dest_reg &= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - sign_extended_imm;
        update_ZF_FLAG(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_FLAG = (regs.EFLAGS & SF_FLAG) != 0;
    bool OF_FLAG = (regs.EFLAGS & OF_FLAG) != 0;
    if (SF_FLAG != OF_FLAG) {
        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_FLAG(byte);

            // Для `REPNE` можно добавить условия выхода
            if (is_repne && (regs.EFLAGS & ZF_FLAG)) {
                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_FLAG(byte);
    }
}
void Emulator::instr_ADD_rm8_r8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Source register (r8)
    uint8_t rm = modrm & 0x07;              // Destination (r/m8)

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

    if (mod == 3) { // Register to register
        uint8_t* dest_reg = get_register8_by_code(rm);
        if (!dest_reg) {
            std::cout << "Unknown destination register in ADD r/m8, r8.\n";
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg += *src_reg;
        update_ZF_FLAG(*dest_reg);
    }
    else {
        // Memory operand
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        uint8_t value = read_memory_byte(address);
        value += *src_reg;
        write_memory_byte(address, value);
        update_ZF_FLAG(value);
    }
    // Update other flags (CF_FLAG, OF_FLAG, etc.) as necessary
}
// XOR AL, imm8
void Emulator::instr_XOR_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX); // Access the AL register
    *al ^= imm8; // Perform XOR operation

    // Update Zero Flag (ZF_FLAG)
    if (*al == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;

    // Update Sign Flag (SF_FLAG)
    if (*al & 0x80)
        regs.EFLAGS |= SF_FLAG;
    else
        regs.EFLAGS &= ~SF_FLAG;

    // Parity Flag (PF)
    update_PF(*al);

    // Clear Carry Flag (CF_FLAG) and Overflow Flag (OF_FLAG) as XOR resets them
    regs.EFLAGS &= ~CF_FLAG;
    regs.EFLAGS &= ~OF_FLAG;

    std::cout << "Выполнена инструкция XOR AL, imm8. AL: 0x" << std::hex << static_cast<int>(*al) << "\n";
}

// Function to update Parity Flag based on the result
void Emulator::update_PF(uint8_t result) {
    // Count the number OF_FLAG set bits
    result ^= result >> 4;
    result &= 0xF;
    bool parity = (0x6996 >> result) & 1;
    if (parity)
        regs.EFLAGS |= PF_FLAG; // PF is set if parity is even
    else
        regs.EFLAGS &= ~PF_FLAG;
}
void Emulator::instr_AND_rm8_r8() {
    uint8_t modrm = fetch_byte();

    uint8_t mod = (modrm >> 6) & 0x03;
    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 source register in AND r/m8, r8.\n";
        error_flag = true;
        running = false;
        return;
    }

    uint8_t value; // Объявляем переменную value

    if (mod == 3) { // Режим регистр-регистр
        uint8_t* dest_reg = get_register8_by_code(rm);
        if (!dest_reg) {
            std::cout << "Unknown destination register in AND r/m8, r8.\n";
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg &= *reg;
        value = *dest_reg; // Сохраняем результат операции
        update_ZF_FLAG(value);
    }
    else {
        // Операнд - память
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        value = read_memory_byte(address);
        value &= *reg;
        write_memory_byte(address, value);
        update_ZF_FLAG(value);
    }

    // Обновление флагов
    // Флаги CF_FLAG и OF_FLAG сбрасываются при логических операциях
    regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);

    // Обновление SF_FLAG
    if ((value & 0x80) != 0)
        regs.EFLAGS |= SF_FLAG;
    else
        regs.EFLAGS &= ~SF_FLAG;

    // Обновление PF
    update_PF(value);

    std::cout << "Выполнена инструкция AND r/m8, r8.\n";
}
void Emulator::instr_INSB() {
    try {
        // Debug: Print EDI and DF before executing INSB
        std::cout << "Executing INSB:\n";
        std::cout << "EDI: 0x" << std::hex << regs.EDI << "\n";
        std::cout << "DF (Direction Flag): " << ((regs.EFLAGS & DF_FLAG) ? "1" : "0") << "\n";

        uint32_t port = regs.EDX;   // Input port from EDX
        uint32_t address = regs.EDI; // Destination address in ES:(E)DI

        // For simplicity, we'll mock the input operation.
        // In a real emulator, you'd interface with emulated hardware devices.
        uint8_t input_byte = 0x00; // Mocked input byte

        // Write the byte to the destination address
        write_memory_byte(address, input_byte);

        // Update DI based on the Direction Flag (DF)
        if (regs.EFLAGS & DF_FLAG) { // DF is the Direction Flag
            regs.EDI -= 1;
        }
        else {
            regs.EDI += 1;
        }

        std::cout << "Executed INSB. Input byte: 0x" << std::hex << (int)input_byte
            << " stored at address: 0x" << address << "\n";
        std::cout << "Updated EDI: 0x" << regs.EDI << "\n";
    }
    catch (const std::exception& e) {
        std::cerr << "Exception in INSB handler: " << e.what() << "\n";
        error_flag = true;
        running = false;
    }
}
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;
        }
    }
}
#ifndef EMULATOR_H
#define EMULATOR_H

#include <vector>
#include <unordered_map>
#include <functional>
#include <cstdint>

class Emulator {
public:
    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
    };
    struct Operand {
        bool is_memory;
        uint32_t address; // Если is_memory = true
        uint32_t register_code; // Если is_memory = false
    };

    Operand decode_operand(uint8_t modrm);

    Emulator(size_t memory_size);
    void load_program(const std::vector<uint8_t>& program, size_t load_address, bool set_eip);
    void run();
    void print_registers(bool hex_output = false) const;
    bool has_error() const { return error_flag; }

    // Добавленные методы
    void write_memory(uint32_t address, const uint8_t* data, size_t size);
    size_t get_memory_size() const { return memory.size(); }
    void set_eip(uint32_t address);
    void reset_prefixes();
    void initialize_stack();
    struct Registers {
        uint32_t EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP;
        uint32_t EIP;
        uint32_t EFLAGS;
        // Сегментные регистры
        uint32_t CS;
        uint32_t DS;
        uint32_t SS;
        uint32_t ES;
        uint32_t FS;
        uint32_t GS;
        // Флаги для префиксов
        bool lock_prefix = false;
        bool rep_prefix = false;
        bool repne_prefix = false;
        bool operand_size_override = false;
        bool address_size_override = false;
        // Конструктор для инициализации сегментных регистров
        Registers() : EAX(0), EBX(0), ECX(0), EDX(0),
            ESI(0), EDI(0), ESP(0), EBP(0),
            EIP(0), EFLAGS(0),
            CS(0), DS(0), SS(0), ES(0), FS(0), GS(0) {}
    } regs;
private:
    std::vector<uint8_t> memory;
    bool running = false;
    bool error_flag = false;
    uint32_t current_brk = 0;
    uint32_t data_segment_start = 0x08000000; // Начальный адрес сегмента данных
    // Метод для сброса сегментных префиксов
    void reset_segment_override();
    // Метод для установки сегментного префикса
    void set_segment_override(uint8_t prefix);
    // Flags
    const uint32_t CF_FLAG = 1 << 0;   // Carry Flag
    const uint32_t PF_FLAG = 1 << 2;   // Parity Flag
    const uint32_t AF_FLAG = 1 << 4;   // Auxiliary Carry Flag
    const uint32_t ZF_FLAG = 1 << 6;   // Zero Flag
    const uint32_t SF_FLAG = 1 << 7;   // Sign Flag
    const uint32_t OF_FLAG = 1 << 11;  // Overflow Flag
    const uint32_t DF_FLAG = 1 << 10;  // Direction Flag
    const uint32_t IF_FLAG = 1 << 9;   // Interrupt Enable Flag
    const uint32_t PF_FLAG_MASK = 0x00000004; // Parity Flag
    // Instruction handling
    typedef void (Emulator::* InstructionHandler)();
    std::unordered_map<uint8_t, InstructionHandler> instruction_set;
    std::unordered_map<uint8_t, InstructionHandler> extended_instruction_set;
    void initialize_instruction_set();

    // Объявление указателей на текущие сегменты
    uint32_t* current_data_segment;
    uint32_t* current_code_segment;

    // Instruction implementations
    void instr_MOV_Ev_Iv();
    void instr_MOV_EAX_imm32();
    void instr_MOV_EBX_imm32();
    void instr_MOV_ECX_imm32();
    void instr_MOV_EDX_imm32();
    void instr_ADD_EAX_imm32();
    void instr_SUB_EAX_imm32();
    void instr_INC_EAX();
    void instr_DEC_EAX();
    void instr_MUL_EAX();
    void instr_JMP_rel32();
    void instr_CMP_reg_imm8();
    void instr_JE_rel8();
    void instr_JNE_rel8();
    void instr_AND_EAX_imm32();
    void instr_AND_ECX_imm32();
    void instr_OR_EAX_imm32();
    void instr_XOR_EAX_imm32();
    void instr_SUB_r32_imm32();
    void instr_CMP_EAX_imm32();
    void instr_OR_ECX_imm32();
    void instr_RET();
    void instr_MOV_MEM_EAX();
    void instr_MOV_EAX_MEM();
    void instr_CMP_EAX_EBX();
    void instr_JG_rel8();
    void instr_JL_rel8();
    void instr_CMP_r32_rm32();
    void instr_IMUL_reg_rm32_imm32();
    void instr_JB_rel8();
    void instr_JA_rel8();
    void instr_INC_ECX();
    void instr_JMP_rel8();
    void instr_MOV_r8_imm8();
    void instr_SUB_AL_imm8();
    void instr_SUB_rm8_imm8();
    void instr_MOV_rm8_r8();
    void instr_MOV_rm8_imm8();
    void instr_MOV_r8_rm8();
    void instr_ADD_AL_imm8();
    void instr_MOV_ESI_imm32();
    void instr_INT();
    void instr_F7();
    void instr_MUL_rm32(uint8_t modrm);
    void instr_DIV_rm32(uint8_t modrm);
    void instr_IDIV_rm32(uint8_t modrm);
    void instr_XOR_r32_rm32();
    void instr_MOV_r32_rm32();
    void instr_ADD_rm32_r32();
    void instr_CMP_AL_imm8();
    void instr_ADD_r32_rm32();
    void instr_SUB_EBX_imm32();
    void instr_IMUL_reg_rm32_imm8();
    void instr_MOV_r32_r_m32();
    void instr_MOV_EBP_imm32();
    void instr_MOV_ESP_imm32();
    void instr_MOV_EDI_imm32();
    void instr_CALL_rel32();
    void instr_GROUP1_Ev_Iz_81();
    void instr_GROUP1_Ev_Iz_83();
    void instr_LEA_r32_m();
    void instr_MOVSB();
    void instr_JNE_rel32();
    void instr_JG_rel32();
    void instr_JE_rel32();
    void instr_NOP_EAX();
    void instr_NOP_m16_m32();
    void instr_JL_rel32();
    void instr_STI();
    void instr_ENDBR32();
    void instr_PUSH_EDI();
    void instr_PUSH_ESI();
    void instr_PUSH_EBP();
    void instr_PUSH_EBX();
    void instr_PUSH_EDX();
    void instr_PUSH_ECX();
    void instr_PUSH_EAX();
    void instr_PUSH_ESP();
    void instr_POP_EAX();
    void instr_POP_ECX();
    void instr_POP_EDX();
    void instr_POP_EBX();
    void instr_POP_ESP();
    void instr_POP_EBP();
    void instr_POP_ESI();
    void instr_POP_EDI();
    void instr_PUSH_imm8();
    void instr_GROUP5();
    void instr_INC_rm32(uint8_t modrm);
    void instr_DEC_rm32(uint8_t modrm);
    void instr_CALL_rm32(uint8_t modrm);
    void instr_JMP_rm32(uint8_t modrm);
    void instr_PUSH_rm32(uint8_t modrm);
    void instr_PUSH_imm32();
    void instr_ADD_rm8_r8();
    void instr_CLD();
    void instr_NOP();
    void instr_STD();
    void instr_PUSHAD();
    void instr_REP_MOVSB();
    void instr_XOR_AL_imm8();
    void instr_LEAVE();
    void instr_AND_rm8_r8();
    void instr_NOT_rm32(uint8_t modrm);
    void instr_TEST_rm32_r32();
    void instr_INSB();
    // Utility methods
    uint8_t fetch_byte();
    uint32_t fetch_dword();
    uint32_t* get_register_by_code(uint8_t code);
    uint8_t* get_register8_by_code(uint8_t code);
    uint8_t regm_rm(uint8_t modrm);
    uint32_t calculate_address(uint8_t modrm);
    uint32_t calculate_sib_address(uint8_t mod, uint8_t sib, int32_t displacement);
    void update_ZF_FLAG(uint32_t result);
    void update_PF(uint8_t result);
    uint8_t read_memory_byte(uint32_t address) const;
    uint32_t read_memory_dword(uint32_t address) const;
    void write_memory_dword(uint32_t address, uint32_t value);
    void write_memory_byte(uint32_t address, uint8_t value);
    uint32_t allocate_memory(uint32_t addr, uint32_t length);
    void push(uint32_t value);
};

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

// Конструктор
Emulator::Emulator(size_t memory_size) {
    memory.resize(memory_size, 0);
    initialize_instruction_set();
    regs.EAX = regs.EBX = regs.ECX = regs.EDX = regs.ESI = regs.EDI = 0;
    regs.ESP = static_cast<uint32_t>(memory_size - 16);
    initialize_stack();
    regs.CS = regs.DS = regs.SS = regs.ES = regs.FS = regs.GS = 0;

    current_data_segment = &regs.DS;
    current_code_segment = &regs.CS;
    current_brk = data_segment_start;
    regs.EDI = data_segment_start;
}
uint32_t Emulator::allocate_memory(uint32_t addr, uint32_t length) {
    // Простая реализация: просто сдвигаем brk
    if (addr == 0) {
        addr = current_brk;
    }

    uint32_t new_brk = addr + length;
    if (new_brk > memory.size()) {
        // Недостаточно памяти в эмуляторе
        return 0;
    }

    current_brk = new_brk;
    return addr;
}
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 {
            //std::cout << "EIP: 0x" << std::hex << regs.EIP << "\n";
            //std::cout << "ESP: 0x" << std::hex << regs.ESP << "\n";


             // Обработка префиксов
            bool prefix_present;
            do {
                prefix_present = false;
                uint8_t prefix = fetch_byte();

                switch (prefix) {
                case 0xF0:
                    regs.lock_prefix = true;
                    prefix_present = true;
                    break;
                case 0xF2:
                    regs.repne_prefix = true;
                    prefix_present = true;
                    break;
                case 0xF3:
                    regs.rep_prefix = true;
                    prefix_present = true;
                    break;
                case 0x2E: // CS
                case 0x36: // SS
                case 0x3E: // DS
                case 0x26: // ES
                case 0x64: // FS
                case 0x65: // GS
                    set_segment_override(prefix);
                    prefix_present = true;
                    break;
                case 0x66: // Operand-size override
                    regs.operand_size_override = true;
                    prefix_present = true;
                    break;
                case 0x67: // Address-size override
                    regs.address_size_override = true;
                    prefix_present = true;
                    break;
                default:
                    // Если байт не является префиксом, отматываем EIP назад и прекращаем обработку префиксов
                    regs.EIP--;
                    prefix_present = false;
                    break;
                }
            } while (prefix_present);

            // Fetch and print the opcode
            uint8_t opcode = fetch_byte();
            //std::cout << "Opcode: 0x" << std::hex << (int)opcode << "\n";
            // Handle extended opcodes
            if (opcode == 0x0F) {
                opcode = fetch_byte();
                auto it = extended_instruction_set.find(opcode);
                if (it != extended_instruction_set.end()) {
                    InstructionHandler handler = it->second;
                    (this->*handler)();
                }
                else {
                    std::cout << "Unknown extended opcode: 0x0F 0x"
                        << std::hex << (int)opcode << "\n";
                    error_flag = true;
                    running = false;
                }
            }
            else {
                // Standard one-byte opcode
                auto it = instruction_set.find(opcode);
                if (it != instruction_set.end()) {
                    InstructionHandler handler = it->second;
                    (this->*handler)();
                }
                else {
                    std::cout << "Unknown opcode: 0x" << std::hex << (int)opcode << "\n";
                    error_flag = true;
                    running = false;
                }
            }

            // After executing the instruction, print register values
            //print_registers(true);
            // Reset prefixes after instruction execution
            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_FLAG 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[0x20] = &Emulator::instr_AND_rm8_r8;
    instruction_set[0xC7] = &Emulator::instr_MOV_Ev_Iv;
    instruction_set[0x34] = &Emulator::instr_XOR_AL_imm8;
    instruction_set[0x50] = &Emulator::instr_PUSH_EAX;
    instruction_set[0x51] = &Emulator::instr_PUSH_ECX;
    instruction_set[0x52] = &Emulator::instr_PUSH_EDX;
    instruction_set[0x53] = &Emulator::instr_PUSH_EBX;
    instruction_set[0x54] = &Emulator::instr_PUSH_ESP;
    instruction_set[0x55] = &Emulator::instr_PUSH_EBP;
    instruction_set[0x56] = &Emulator::instr_PUSH_ESI;
    instruction_set[0x57] = &Emulator::instr_PUSH_EDI;
    instruction_set[0x6A] = &Emulator::instr_PUSH_imm8;
    instruction_set[0x58] = &Emulator::instr_POP_EAX;
    instruction_set[0x59] = &Emulator::instr_POP_ECX;
    instruction_set[0x5A] = &Emulator::instr_POP_EDX;
    instruction_set[0x5B] = &Emulator::instr_POP_EBX;
    instruction_set[0x5C] = &Emulator::instr_POP_ESP;
    instruction_set[0x5D] = &Emulator::instr_POP_EBP;
    instruction_set[0x5E] = &Emulator::instr_POP_ESI;
    instruction_set[0x5F] = &Emulator::instr_POP_EDI;
    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;
    instruction_set[0xA3] = &Emulator::instr_MOV_MEM_EAX;
    instruction_set[0xA1] = &Emulator::instr_MOV_EAX_MEM;
    instruction_set[0xCD] = &Emulator::instr_INT;
    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;
    instruction_set[0x7F] = &Emulator::instr_JG_rel8;
    instruction_set[0x7C] = &Emulator::instr_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;
    instruction_set[0x6B] = &Emulator::instr_IMUL_reg_rm32_imm8;
    instruction_set[0x8B] = &Emulator::instr_MOV_r32_r_m32;
    instruction_set[0xBB] = &Emulator::instr_MOV_EBX_imm32;
    instruction_set[0xBD] = &Emulator::instr_MOV_EBP_imm32;
    instruction_set[0xBC] = &Emulator::instr_MOV_ESP_imm32;
    instruction_set[0xBE] = &Emulator::instr_MOV_ESI_imm32;
    instruction_set[0xBF] = &Emulator::instr_MOV_EDI_imm32;
    instruction_set[0xE8] = &Emulator::instr_CALL_rel32;
    instruction_set[0x8D] = &Emulator::instr_LEA_r32_m;
    instruction_set[0xA4] = &Emulator::instr_MOVSB;
    instruction_set[0x5E] = &Emulator::instr_POP_ESI;
    instruction_set[0xFF] = &Emulator::instr_GROUP5;
    instruction_set[0x68] = &Emulator::instr_PUSH_imm32;
    instruction_set[0x00] = &Emulator::instr_ADD_rm8_r8;
    instruction_set[0xFC] = &Emulator::instr_CLD;
    instruction_set[0x90] = &Emulator::instr_NOP;
    instruction_set[0xFD] = &Emulator::instr_STD;
    instruction_set[0x60] = &Emulator::instr_PUSHAD;
    instruction_set[0x5D] = &Emulator::instr_POP_EBP;
    instruction_set[0xFB] = &Emulator::instr_STI;
    instruction_set[0xC9] = &Emulator::instr_LEAVE;
    instruction_set[0x85] = &Emulator::instr_TEST_rm32_r32;
    instruction_set[0x6C] = &Emulator::instr_INSB;
    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_ENDBR32;    
}
void Emulator::initialize_stack() {
    // Set stack top a bit below the end OF_FLAG memory
    uint32_t stack_top = memory.size() - 16;

    // Let's assume argc = 0 for simplicity
    uint32_t argc = 0;

    // Set up the initial stack:
    // [ESP + 0]: argc (0)
    // [ESP + 4]: null pointer (argv terminator)
    // [ESP + 8]: null pointer (envp terminator)

    regs.ESP = stack_top - 12; // Move ESP to leave space for 3 values

    // Push envp terminator (null pointer)
    write_memory_dword(regs.ESP + 8, 0);

    // Push argv terminator (null pointer)
    write_memory_dword(regs.ESP + 4, 0);

    // Push argc (0)
    write_memory_dword(regs.ESP + 0, argc);

    // Optionally, you can show what's on the stack now for debugging
    std::cout << "Stack initialized with argc and null terminators.\n";
}
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_FLAG(*dest_reg);
    // Update other flags (CF_FLAG, OF_FLAG) 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_FLAG)
void Emulator::update_ZF_FLAG(uint32_t result) {
    if (result == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
}

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

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)
}
Серьезность	Код	Описание	Проект	Файл	Строка	Состояние подавления	Подробности
Ошибка	C4700	использована неинициализированная локальная переменная "OF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1286		
Предупреждение	C6001	Использование неинициализированной памяти "ZF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	763		
Предупреждение	C6001	Использование неинициализированной памяти "SF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	764		
Предупреждение	C6001	Использование неинициализированной памяти "OF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	765		
Предупреждение	C26819	Неаннотированная передача управления между метками switch (es.78).	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1103		
Предупреждение	C6001	Использование неинициализированной памяти "ZF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1284		
Предупреждение	C6001	Использование неинициализированной памяти "SF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1285		
Предупреждение	C6001	Использование неинициализированной памяти "OF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1286		
Предупреждение	C6001	Использование неинициализированной памяти "CF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1373		
Предупреждение	C6001	Использование неинициализированной памяти "ZF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1374		
Предупреждение	C6001	Использование неинициализированной памяти "SF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1692		
Предупреждение	C6001	Использование неинициализированной памяти "OF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1693		
Предупреждение	C6001	Использование неинициализированной памяти "SF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1860		
Предупреждение	C6001	Использование неинициализированной памяти "OF_FLAG".	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1861		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	763		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	764		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	765		
Предупреждение	C4267	=: преобразование из "size_t" в "uint32_t"; возможна потеря данных	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1096		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1284		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1285		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1286		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1373		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1374		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1692		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1693		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1860		
Предупреждение	C4805	&: небезопасное смешение типа "uint32_t" и типа "bool" в операции	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1861		
Ошибка	C4700	использована неинициализированная локальная переменная "ZF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	763		
Ошибка	C4700	использована неинициализированная локальная переменная "SF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1860		
Ошибка	C4700	использована неинициализированная локальная переменная "ZF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1284		
Ошибка	C4700	использована неинициализированная локальная переменная "CF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1373		
Ошибка	C4700	использована неинициализированная локальная переменная "SF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1692		
Ошибка	C4700	использована неинициализированная локальная переменная "SF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	764		
Ошибка	C4700	использована неинициализированная локальная переменная "OF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	765		
Ошибка	C4700	использована неинициализированная локальная переменная "SF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1285		
Ошибка	C4700	использована неинициализированная локальная переменная "OF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1861		
Ошибка	C4700	использована неинициализированная локальная переменная "ZF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1374		
Ошибка	C4700	использована неинициализированная локальная переменная "OF_FLAG"	x86_Emulator	C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp	1693