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

// Конструктор
Emulator::Emulator(size_t memory_size) {
    memory.resize(memory_size, 0);
    initialize_instruction_set();
}

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 |= memory[address];
    value |= memory[address + 1] << 8;
    value |= memory[address + 2] << 16;
    value |= memory[address + 3] << 24;
    return value;
}

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

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

            // Проверка на префиксы
            const std::vector<uint8_t> prefixes = { /* префиксы */ };
            while (std::find(prefixes.begin(), prefixes.end(), opcode) != prefixes.end()) {
                std::cout << "Пропуск префикса: 0x" << std::hex << (int)opcode << "\n";
                opcode = fetch_byte();
            }

            auto it = instruction_set.find(opcode);
            if (it != instruction_set.end()) {
                InstructionHandler handler = it->second;
                (this->*handler)();
            }
            else {
                std::cout << "Неизвестный opcode: 0x" << std::hex << (int)opcode << "\n";
                error_flag = true; // Установка флага ошибки
                running = false;
            }
        }
        catch (const std::runtime_error& e) {
            std::cerr << "Runtime error: " << e.what() << "\n";
            error_flag = true; // Установка флага ошибки
            running = false;
        }
    }
}

// Метод 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;
    uint32_t address = 0;

    if (mod == 0) {
        if (rm == 5) {
            // [disp32]
            uint32_t disp32 = fetch_dword();
            address = disp32;
        }
        else if (rm == 4) {
            // SIB байт без смещения
            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 байт с 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 байт с disp32
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp32);
        }
        else {
            // [reg + disp32]
            address = *get_register_by_code(rm) + disp32;
        }
    }
    else {
        std::cout << "Unsupported ModR/M mod value in calculate_address.\n";
        error_flag = true;
        running = false;
        return 0;
    }

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

    return address;
}

// Инициализация таблицы инструкций
void Emulator::initialize_instruction_set() {
    instruction_set[0xB8] = &Emulator::instr_MOV_EAX_imm32;
    instruction_set[0xBB] = &Emulator::instr_MOV_EBX_imm32;
    instruction_set[0xB9] = &Emulator::instr_MOV_ECX_imm32;
    instruction_set[0xBA] = &Emulator::instr_MOV_EDX_imm32;
    instruction_set[0x05] = &Emulator::instr_ADD_EAX_imm32;
    instruction_set[0x2D] = &Emulator::instr_SUB_EAX_imm32;
    instruction_set[0x40] = &Emulator::instr_INC_EAX;
    instruction_set[0x48] = &Emulator::instr_DEC_EAX;
    instruction_set[0xF7] = &Emulator::instr_F7;
    instruction_set[0xE9] = &Emulator::instr_JMP_rel32;
    instruction_set[0x83] = &Emulator::instr_CMP_reg_imm8;
    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_SUB_r32_imm32; // Обработчик SUB r32, imm32
    instruction_set[0x3D] = &Emulator::instr_CMP_EAX_imm32;
    instruction_set[0x0E] = &Emulator::instr_OR_ECX_imm32;
    instruction_set[0xC3] = &Emulator::instr_RET; // Обработчик RET
    instruction_set[0xA3] = &Emulator::instr_MOV_MEM_EAX; // MOV [address], EAX
    instruction_set[0xA1] = &Emulator::instr_MOV_EAX_MEM; // MOV EAX, [address]
    instruction_set[0xCD] = &Emulator::instr_INT; // INT n
    instruction_set[0x89] = &Emulator::instr_MOV_r32_rm32;
    instruction_set[0x31] = &Emulator::instr_XOR_r32_rm32;
    instruction_set[0xBE] = &Emulator::instr_MOV_ESI_imm32;
    instruction_set[0x04] = &Emulator::instr_ADD_AL_imm8;
    instruction_set[0x88] = &Emulator::instr_MOV_rm8_r8;
    instruction_set[0xC6] = &Emulator::instr_MOV_rm8_imm8;
    instruction_set[0x39] = &Emulator::instr_CMP_r32_rm32; // CMP r/m32, r32
    instruction_set[0x7F] = &Emulator::instr_JG_rel8;     // JG rel8
    instruction_set[0x7C] = &Emulator::instr_JL_rel8;     // JL rel8
    instruction_set[0x8A] = &Emulator::instr_MOV_r8_rm8;
    instruction_set[0x80] = &Emulator::instr_SUB_rm8_imm8;
    instruction_set[0xB7] = &Emulator::instr_MOV_r8_imm8;
    instruction_set[0x69] = &Emulator::instr_IMUL_reg_rm32_imm32;
    instruction_set[0x72] = &Emulator::instr_JB_rel8;
    instruction_set[0x77] = &Emulator::instr_JA_rel8;
    instruction_set[0x41] = &Emulator::instr_INC_ECX;
    instruction_set[0xEB] = &Emulator::instr_JMP_rel8;
    instruction_set[0x2C] = &Emulator::instr_SUB_AL_imm8;
    instruction_set[0x3C] = &Emulator::instr_CMP_AL_imm8;
    instruction_set[0x01] = &Emulator::instr_ADD_rm32_r32;
}
void Emulator::write_memory_dword(uint32_t address, uint32_t value) {
    if (address + 4 > memory.size()) {
        std::cout << "Memory write out of bounds at address: 0x" << std::hex << address << "\n";
        error_flag = true;
        running = false;
        return;
    }
    memory[address] = value & 0xFF;
    memory[address + 1] = (value >> 8) & 0xFF;
    memory[address + 2] = (value >> 16) & 0xFF;
    memory[address + 3] = (value >> 24) & 0xFF;
}
// Обновление Zero Flag (ZF)
void Emulator::update_ZF(uint32_t result) {
    if (result == 0)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;
}

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

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

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

    // Debug output before incrementing EIP
    //std::cout << "fetch_dword: прочитано значение 0x" << std::hex << value << " из EIP = 0x" << regs.EIP << "\n";

    regs.EIP += 4; // Correctly increment EIP by 4 bytes after reading

    // Debug output after incrementing EIP
    //std::cout << "fetch_dword: новый EIP = 0x" << std::hex << regs.EIP << "\n";

    return value;
}

uint32_t* Emulator::get_register_by_code(uint8_t code) {
    switch (code) {
    case 0: return &regs.EAX;
    case 1: return &regs.ECX;
    case 2: return &regs.EDX;
    case 3: return &regs.EBX;
    case 4: return &regs.ESP;
    case 5: return &regs.EBP;
    case 6: return &regs.ESI;
    case 7: return &regs.EDI;
    default: return nullptr;
    }
}
uint8_t* Emulator::get_register8_by_code(uint8_t code) {
    switch (code) {
    case 0: return reinterpret_cast<uint8_t*>(&regs.EAX);          // AL
    case 1: return reinterpret_cast<uint8_t*>(&regs.ECX);          // CL
    case 2: return reinterpret_cast<uint8_t*>(&regs.EDX);          // DL
    case 3: return reinterpret_cast<uint8_t*>(&regs.EBX);          // BL
    case 4: return reinterpret_cast<uint8_t*>(&regs.EAX) + 1;      // AH
    case 5: return reinterpret_cast<uint8_t*>(&regs.ECX) + 1;      // CH
    case 6: return reinterpret_cast<uint8_t*>(&regs.EDX) + 1;      // DH
    case 7: return reinterpret_cast<uint8_t*>(&regs.EBX) + 1;      // BH
    default: return nullptr;
    }
}
uint8_t Emulator::regm_rm(uint8_t modrm) {
    return modrm & 0x07; // Извлекаем регистровый код (rm)
}
// Instructions.cpp
#include "Emulator.h"
#include <iostream>
#include <stdint.h>
#include <string>
// Реализация обработчиков инструкций

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

// 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() {
    uint32_t imm = fetch_dword();
    regs.EAX += imm;
    update_ZF(regs.EAX);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Обработчик инструкции RET
void Emulator::instr_RET() {
    running = false; // Завершаем выполнение программы
}

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

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

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

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

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

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

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

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

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

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

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

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

    // Overflow Flag (OF)
    uint32_t sign_rm = *rm & 0x80000000;
    uint32_t sign_reg = *reg & 0x80000000;
    uint32_t sign_result = result & 0x80000000;
    if ((sign_rm != sign_reg) && (sign_rm != sign_result))
        regs.EFLAGS |= OF;
    else
        regs.EFLAGS &= ~OF;
}
void Emulator::instr_MOV_rm8_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm & 0xC0) >> 6;
    // uint8_t reg = (modrm & 0x38) >> 3; // Не используется для MOV r/m8, imm8
    uint8_t rm = (modrm & 0x07);       // Назначение: r/m8

    uint8_t imm8 = fetch_byte();

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

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

        memory[address] = imm8;
    }
}

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

    uint32_t operand = 0;

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

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

    update_ZF(regs.EAX);
}

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

    uint32_t operand = 0;

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

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

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

void Emulator::instr_IDIV_rm32(uint8_t modrm) {
    uint8_t mod = (modrm & 0xC0) >> 6;
    uint8_t rm = (modrm & 0x07);       // Источник: r/m32

    int32_t operand = 0;

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

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

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

    update_ZF(regs.EAX);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    uint8_t modrm = fetch_byte(); // Считываем ModRM байт
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Регистр назначения
    uint8_t rm_code = modrm & 0x07;         // Регистр источника

    // Отладочный вывод
    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 после 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) { // Режим регистр-регистр
        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;
    }

    // Перед считыванием imm32, EIP указывает на него
    std::cout << "EIP перед fetch_dword (imm32): 0x" << std::hex << regs.EIP << "\n";

    uint32_t imm32 = fetch_dword(); // Считываем непосредственное значение imm32

    // После считывания imm32, EIP должен быть увеличен на 4
    std::cout << "EIP после fetch_dword (imm32): 0x" << std::hex << regs.EIP << "\n";

    // Отладочный вывод значения imm32
    std::cout << "Immediate value: " << std::dec << imm32 << "\n";

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

    // Выполняем умножение
    *dest_reg = (*src_reg) * imm32;

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

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

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

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

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

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

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

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

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

    *dest -= imm8;

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

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

    uint32_t address = 0;

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

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

    *reg = memory[address];
}
void Emulator::instr_ADD_rm32_r32() {
    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* src_reg = get_register_by_code(reg_code);

    if (mod == 3) { // Режим регистр-регистр
        uint32_t* dest_reg = get_register_by_code(rm_code);
        if (src_reg && dest_reg) {
            *dest_reg += *src_reg;
            update_ZF(*dest_reg);
            // Обновите другие флаги, если необходимо (Carry, Overflow и т.д.)
        }
        else {
            std::cout << "Неизвестный регистр в ADD r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    else { // Операнд r/m32 является памятью
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;

        uint32_t value = read_memory_dword(address);
        value += *src_reg;
        // Записываем результат обратно в память
        write_memory_dword(address, value);
        update_ZF(value);
        // Обновите другие флаги, если необходимо
    }
}
void Emulator::instr_CMP_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t al = regs.EAX & 0xFF;
    uint8_t result = al - imm8;

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

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

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

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

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

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

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

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

        if (src_reg && dest_reg) {
            *dest_reg ^= *src_reg;
            update_ZF(*dest_reg);
        }
        else {
            std::cout << "Unknown register in XOR r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    // ...
}

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

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

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

// Тест для Hello World
bool run_hello_world_test() {
    Emulator emulator(1024 * 1024); // 1 МБ памяти

    // Машинный код программы Hello World
    std::vector<uint8_t> program = {
        // mov eax, 4          ; sys_write
        0xB8, 0x04, 0x00, 0x00, 0x00,
        // mov ebx, 1          ; stdout
        0xBB, 0x01, 0x00, 0x00, 0x00,
        // mov ecx, 0x1000     ; адрес сообщения
        0xB9, 0x00, 0x10, 0x00, 0x00,
        // mov edx, 14         ; длина сообщения
        0xBA, 0x0E, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80,
        // mov eax, 1          ; sys_exit
        0xB8, 0x01, 0x00, 0x00, 0x00,
        // mov ebx, 0          ; код выхода
        0xBB, 0x00, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80
    };

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

    // Загрузка данных (строка "Hello, World!\n") в память по адресу 0x1000 без установки EIP
    std::vector<uint8_t> data = {
        'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\n'
    };
    emulator.load_program(data, 0x1000, false);

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

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

// Тест для калькулятора с преобразованием числа в строку
bool run_calculator_test() {
    Emulator emulator(1024 * 1024); // 1 МБ памяти

    // Машинный код программы калькулятора
    std::vector<uint8_t> program = {
        // mov eax, 5          ; Загружаем 5 в EAX
        0xB8, 0x05, 0x00, 0x00, 0x00,
        // add eax, 7          ; Добавляем 7 к EAX (EAX = 12)
        0x05, 0x07, 0x00, 0x00, 0x00,
        // mov [0x2000], eax   ; Сохраняем результат (12) по адресу 0x2000
        0xA3, 0x00, 0x20, 0x00, 0x00,
        // mov ebx, eax        ; Копируем EAX в EBX
        0x89, 0xC3,
        // mov ecx, 0x3000     ; Адрес строки суммы
        0xB9, 0x00, 0x30, 0x00, 0x00,
        // xor edx, edx        ; Обнуляем EDX перед делением
        0x31, 0xD2,
        // mov esi, 10         ; Загружаем 10 в ESI
        0xBE, 0x0A, 0x00, 0x00, 0x00,
        // div esi             ; Делим EAX на ESI, результат в EAX, остаток в EDX
        0xF7, 0xF6,
        // add al, '0'         ; Преобразуем десятки в ASCII
        0x04, 0x30,
        // mov [ecx], al       ; Сохраняем десятки
        0x88, 0x01,
        // mov eax, edx        ; Переносим остаток в EAX
        0x89, 0xD0,
        // add al, '0'         ; Преобразуем единицы в ASCII
        0x04, 0x30,
        // mov [ecx+1], al     ; Сохраняем единицы
        0x88, 0x41, 0x01,
        // mov byte [ecx+2], 0x0A ; Добавляем перевод строки
        0xC6, 0x41, 0x02, 0x0A,
        // mov eax, 4          ; sys_write
        0xB8, 0x04, 0x00, 0x00, 0x00,
        // mov ebx, 1          ; stdout
        0xBB, 0x01, 0x00, 0x00, 0x00,
        // mov ecx, msg        ; Адрес строки префикса "Result: "
        0xB9, 0x00, 0x10, 0x00, 0x00,
        // mov edx, msg_len    ; Длина строки префикса
        0xBA, 0x08, 0x00, 0x00, 0x00,
        // int 0x80            ; Вызов системного прерывания (вывод префикса)
        0xCD, 0x80,
        // mov eax, 4          ; sys_write
        0xB8, 0x04, 0x00, 0x00, 0x00,
        // mov ebx, 1          ; stdout
        0xBB, 0x01, 0x00, 0x00, 0x00,
        // mov ecx, sum_str    ; Адрес строки суммы
        0xB9, 0x00, 0x30, 0x00, 0x00,
        // mov edx, 3          ; Длина строки суммы (2 цифры + перевод строки)
        0xBA, 0x03, 0x00, 0x00, 0x00,
        // int 0x80            ; Вызов системного прерывания (вывод суммы)
        0xCD, 0x80,
        // mov eax, 1          ; sys_exit
        0xB8, 0x01, 0x00, 0x00, 0x00,
        // mov ebx, 0          ; Код выхода 0
        0xBB, 0x00, 0x00, 0x00, 0x00,
        // int 0x80            ; Вызов системного прерывания (завершение программы)
        0xCD, 0x80
    };

    emulator.load_program(program, 0x0000, true);

    // Загрузка данных:
    std::vector<uint8_t> data_prefix = { 'R', 'e', 's', 'u', 'l', 't', ':', ' ' };
    emulator.load_program(data_prefix, 0x1000, false);

    std::vector<uint8_t> data_sum(3, 0); // Инициализируем строку для результата
    emulator.load_program(data_sum, 0x3000, false);

    emulator.run();
    return !emulator.has_error();
}

// Тест для программы "Угадай число"
bool run_guess_number_test() {
    Emulator emulator(1024 * 1024); // 1 МБ памяти

    // Машинный код программы "Угадай число"
    std::vector<uint8_t> program = {
        // Загаданное число 50 (хранится в EAX)
        // mov eax, 50
        0xB8, 0x32, 0x00, 0x00, 0x00,

        // game_loop:
        // Выводим приглашение: "Guess the number: "
        // mov eax, 4          ; sys_write
        0xB8, 0x04, 0x00, 0x00, 0x00,
        // mov ebx, 1          ; stdout
        0xBB, 0x01, 0x00, 0x00, 0x00,
        // mov ecx, prompt_msg ; Адрес строки приглашения
        0xB9, 0x00, 0x40, 0x00, 0x00,
        // mov edx, 18         ; Длина строки приглашения
        0xBA, 0x12, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80,

        // Читаем ввод пользователя
        // mov eax, 3          ; sys_read
        0xB8, 0x03, 0x00, 0x00, 0x00,
        // mov ebx, 0          ; stdin
        0xBB, 0x00, 0x00, 0x00, 0x00,
        // mov ecx, input_buf  ; Адрес буфера для ввода
        0xB9, 0x00, 0x50, 0x00, 0x00,
        // mov edx, 10         ; Максимальное количество байтов для чтения
        0xBA, 0x0A, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80,

        // Преобразуем введённую строку в число (из ASCII в число)
        // xor ebx, ebx           ; Обнуляем EBX (будущий результат)
        0x31, 0xDB,
        // mov ecx, 0x5000        ; Указатель на input_buf
        0xB9, 0x00, 0x50, 0x00, 0x00,

        // convert_loop:
        // mov al, byte [ecx]
        0x8A, 0x01,
        // cmp al, 0
        0x3C, 0x00,
        // je end_convert
        0x74, 0x12,
        // cmp al, 0x0A
        0x3C, 0x0A,
        // je end_convert
        0x74, 0x0D,
        // cmp al, '0'
        0x3C, 0x30,
        // jb invalid_input
        0x72, 0x07,
        // cmp al, '9'
        0x3C, 0x39,
        // ja invalid_input
        0x77, 0x01,
        // sub al, '0'
        0x2C, 0x30,
        // imul ebx, ebx, 10
        0x69, 0xDB, 0x0A, 0x00, 0x00, 0x00,
        // add ebx, eax
        0x01, 0xD8,
        // inc ecx
        0x41,
        // jmp convert_loop
        0xEB, 0xE2,

        // invalid_input:
        // xor ebx, ebx
        0x31, 0xDB,
        // jmp end_convert
        0xEB, 0x05,

        // end_convert:
        // Сравниваем введённое число (в EBX) с загаданным числом (в EAX)
        // cmp eax, ebx
        0x39, 0xD8,

        // jg greater          ; Если EAX > EBX
        0x7F, 0x14,
        // jl smaller          ; Если EAX < EBX
        0x7C, 0x10,

        // Код "Success"
        // mov eax, 4          ; sys_write
        0xB8, 0x04, 0x00, 0x00, 0x00,
        // mov ebx, 1          ; stdout
        0xBB, 0x01, 0x00, 0x00, 0x00,
        // mov ecx, success_msg ; Адрес строки об успехе
        0xB9, 0x00, 0x10, 0x00, 0x00,
        // mov edx, 8          ; Длина строки
        0xBA, 0x08, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80,

        // mov eax, 1          ; sys_exit
        0xB8, 0x01, 0x00, 0x00, 0x00,
        // mov ebx, 0          ; код выхода
        0xBB, 0x00, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80,

        // greater:
        // mov eax, 4          ; sys_write
        0xB8, 0x04, 0x00, 0x00, 0x00,
        // mov ebx, 1          ; stdout
        0xBB, 0x01, 0x00, 0x00, 0x00,
        // mov ecx, greater_msg ; Адрес строки "More!\n"
        0xB9, 0x00, 0x20, 0x00, 0x00,
        // mov edx, 6          ; Длина строки
        0xBA, 0x06, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80,
        // jmp game_loop       ; Переходим к началу игры
        0xEB, 0xA2,           // Смещение рассчитывается относительно текущего EIP

        // smaller:
        // mov eax, 4          ; sys_write
        0xB8, 0x04, 0x00, 0x00, 0x00,
        // mov ebx, 1          ; stdout
        0xBB, 0x01, 0x00, 0x00, 0x00,
        // mov ecx, smaller_msg ; Адрес строки "Less!\n"
        0xB9, 0x00, 0x30, 0x00, 0x00,
        // mov edx, 6          ; Длина строки
        0xBA, 0x06, 0x00, 0x00, 0x00,
        // int 0x80            ; системный вызов
        0xCD, 0x80,
        // jmp game_loop       ; Переходим к началу игры
        0xEB, 0x89,           // Смещение рассчитывается относительно текущего EIP
    };

    emulator.load_program(program, 0x0000, true);

    // Инициализация буфера ввода (заполняем нулями)
    std::vector<uint8_t> input_buf(10, 0);
    emulator.load_program(input_buf, 0x5000, false);

    // Сообщение приглашения
    std::vector<uint8_t> prompt_msg = {
        'G', 'u', 'e', 's', 's', ' ',
        't', 'h', 'e', ' ', 'n', 'u', 'm', 'b', 'e', 'r', ':', ' '
    };
    emulator.load_program(prompt_msg, 0x4000, false);

    // Сообщение об успехе
    std::vector<uint8_t> success_msg = { 'S', 'u', 'c', 'c', 'e', 's', 's', '!', '\n' };
    emulator.load_program(success_msg, 0x1000, false);

    // Сообщение "More!\n"
    std::vector<uint8_t> greater_msg = { 'M', 'o', 'r', 'e', '!', '\n' };
    emulator.load_program(greater_msg, 0x2000, false);

    // Сообщение "Less!\n"
    std::vector<uint8_t> smaller_msg = { 'L', 'e', 's', 's', '!', '\n' };
    emulator.load_program(smaller_msg, 0x3000, false);

    emulator.run();
    return !emulator.has_error();
}

int main() {
    // Тест Hello World
    std::cout << "\nЗапуск теста Hello World...\n";
    bool hello_result = run_hello_world_test();

    if (hello_result) {
        std::cout << "\nТест Hello World пройден!\n";
    }
    else {
        std::cout << "\nТест Hello World не пройден.\n";
    }

    // Тест калькулятора
    std::cout << "\nЗапуск теста Калькулятор...\n";
    bool calculator_result = run_calculator_test();

    if (calculator_result) {
        std::cout << "\nТест Калькулятор пройден!\n";
    }
    else {
        std::cout << "\nТест Калькулятор не пройден.\n";
    }

    // Тест "Угадай число"
    std::cout << "\nЗапуск теста Угадай число...\n";
    bool guess_number_result = run_guess_number_test();

    if (guess_number_result) {
        std::cout << "\nТест Угадай число пройден!\n";
    }
    else {
        std::cout << "\nТест Угадай число не пройден.\n";
    }

    return 0;
}
Запуск теста Hello World...
Hello, World!

Тест Hello World пройден!

Запуск теста Калькулятор...
Result: 12
Тест Калькулятор пройден!

Запуск теста Угадай число...
Guess the number: 50
EIP перед fetch_byte (ModRM): 0x4d
Executing IMUL with modrm: 0xdb
Destination reg code: 3, Source rm code: 3
EIP после fetch_byte (ModRM): 0x4e
EIP перед fetch_dword (imm32): 0x4e
EIP после fetch_dword (imm32): 0x52
Immediate value: 10
Неизвестный opcode: 0xdb

Тест Угадай число не пройден.