#include #include #include #define MEMORY_SIZE 1048576 union reg16 { struct { uint8_t low; uint8_t high; }; uint16_t value; }; struct ModRM { uint8_t mod; // addressing mode uint8_t reg; // source uint8_t rm; // dest }; reg16 AX, BX, CX, DX; // general regs uint16_t SI, DI; // source index, dest index uint16_t BP, SP; // base ptr, stack ptr uint16_t IP; // instruction ptr uint16_t CS, DS, ES, SS; // code segmets reg, data segment reg, extra segment reg, stack segment reg bool CF; // carry bool PF; // parity bool AF; // auxiliary carry bool ZF; // zero bool SF; // sign bool TF; // trap bool IF; // interrupt bool DF; // direction bool OF; // overflow uint8_t ram[MEMORY_SIZE]; uint32_t physical_addr(uint16_t seg, uint16_t offset); bool load_binary(char* filename, size_t addr); ModRM parse_modrm(uint8_t byte); uint8_t get_reg_byte(uint8_t code); void set_reg_byte(uint8_t code, uint8_t value); uint16_t get_reg_word(uint8_t code); void set_reg_word(uint8_t code, uint16_t value); uint16_t get_displacement(uint8_t size); uint32_t calc_effective_addr(ModRM modrm); void update_flags_add(uint8_t b1, uint8_t b2, uint8_t res); void update_flags_add16(uint16_t w1, uint16_t w2, uint16_t res); uint32_t physical_addr(uint16_t seg, uint16_t offset) { return ((uint32_t) seg << 4) + offset; } bool load_binary(char* filename, size_t addr) { std::ifstream file(filename, std::ios::binary); if (!file) { std::cerr << "failed to open file " << filename << "\n"; return false; } file.seekg(0, std::ios::end); size_t file_size = file.tellg(); file.seekg(0, std::ios::beg); if (file_size > MEMORY_SIZE - addr) { std::cerr << "file is too big"; return false; } file.read(reinterpret_cast(ram + addr), file_size); if (!file) { std::cerr << "failed to read entire file"; return false; } std::cout << "file " << filename << " loaded to ram\n"; return true; } ModRM parse_modrm(uint8_t byte) { ModRM modrm; modrm.mod = (byte >> 6) & 0x3; modrm.reg = (byte >> 3) & 0x7; modrm.rm = byte & 0x7; return modrm; } uint8_t get_reg_byte(uint8_t code) { switch (code) { case 0: return AX.low; case 1: return CX.low; case 2: return DX.low; case 3: return BX.low; case 4: return AX.high; case 5: return CX.high; case 6: return DX.high; case 7: return BX.high; default: std::cerr << "invalid reg code for 8-bit reg"; return 0; } } void set_reg_byte(uint8_t code, uint8_t value) { switch (code) { case 0: AX.low = value; break; case 1: CX.low = value; break; case 2: DX.low = value; break; case 3: BX.low = value; break; case 4: AX.high = value; break; case 5: CX.high = value; break; case 6: DX.high = value; break; case 7: BX.high = value; break; default: std::cerr << "invalid reg code for 8-bit reg"; } } uint16_t get_reg_word(uint8_t code) { switch (code) { case 0: return AX.value; case 1: return CX.value; case 2: return DX.value; case 3: return BX.value; case 4: return SP; case 5: return BP; case 6: return SI; case 7: return DI; default: std::cerr << "invalid reg code for 8-bit reg"; return 0; } } void set_reg_word(uint8_t code, uint16_t value) { switch (code) { case 0: AX.value = value; break; case 1: CX.value = value; break; case 2: DX.value = value; break; case 3: BX.value = value; break; case 4: SP = value; break; case 5: BP = value; break; case 6: SI = value; break; case 7: DI = value; break; default: std::cerr << "invalid reg code for 8-bit reg"; break; } } uint16_t get_displacement(uint8_t size) { uint16_t disp = 0; uint32_t addr = physical_addr(CS, IP); if (size == 1) { // 8-bit disp = static_cast(ram[addr]); IP++; } else if (size == 2) { disp = ram[addr] | (ram[addr + 1] << 8); IP += 2; } return disp; } uint32_t calc_effective_addr(ModRM modrm) { uint16_t base = 0; uint16_t disp = 0; bool has_disp = false; switch (modrm.rm) { case 0: base = BX.value + SI; break; case 1: base = BX.value + DI; break; case 2: base = BP + SI; break; case 3: base = BP + DI; break; case 4: base = SI; break; case 5: base = DI; break; case 6: if (modrm.mod == 0) { disp = get_displacement(2); base = 0; // Для прямого адреса } else base = BP; break; case 7: base = BX.value; break; } if (modrm.mod == 1) { disp = get_displacement(1); has_disp = true; } else if (modrm.mod == 2) { disp = get_displacement(2); has_disp = true; } return base + (has_disp ? disp : 0); } void update_flags_add(uint8_t b1, uint8_t b2, uint8_t res) { CF = (static_cast(b1) + static_cast(b2)) > 0xFF; ZF = res == 0; SF = (res & 0x80) != 0; uint8_t count = 0; for (int i = 0; i < 8; ++i) count += (res >> i) & 1; PF = (count % 2) == 0; AF = ((b1 & 0xF) + (b2 & 0xF)) > 0xF; OF = (~(b1 ^ b2) & (b2 ^ res) & 0x80) != 0; } void update_flags_add16(uint16_t w1, uint16_t w2, uint16_t res) { CF = (static_cast(w1) + static_cast(w2)) > 0xFFFF; ZF = (res == 0); SF = (res & 0x8000) != 0; uint8_t low_byte = res & 0xFF; uint8_t count = 0; for (int i = 0; i < 8; i++) count += (low_byte >> i) & 1; PF = (count % 2 == 0); AF = ((w1 & 0xF) + (w2 & 0xF)) > 0xF; OF = ((w1 ^ res) & (w2 ^ res) & 0x8000) != 0; }