From 500ffda8c237a396388eddfa2b3a9a8df286daa8 Mon Sep 17 00:00:00 2001 From: pablusha Date: Sun, 8 Jun 2025 22:28:03 +0300 Subject: [PATCH] added add_eb_gb and add_ev_gv instructions, fixed some stuff ig --- .gitignore | 3 +- emulator.h | 158 ++++++++++++++++++++++++++++++++++++++++++------- instructions.h | 75 +++++++++++++++++++++++ main.cpp | 14 ++++- 4 files changed, 226 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 5d9cae5..aa0fe53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ emulator -pizda \ No newline at end of file +pizda +.vscode/* \ No newline at end of file diff --git a/emulator.h b/emulator.h index e50e107..58bd22b 100644 --- a/emulator.h +++ b/emulator.h @@ -41,7 +41,16 @@ bool load_binary(char* filename, size_t addr); ModRM parse_modrm(uint8_t byte); uint8_t get_reg_byte(uint8_t code); -uint8_t set_reg_byte(uint8_t code, uint8_t value); +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; @@ -82,26 +91,8 @@ ModRM parse_modrm(uint8_t byte) { return modrm; } -uint8_t get_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: AX.high = value; break; - case 6: AX.high = value; break; - case 7: AX.high = value; break; - default: - std::cerr << "invalid reg code for 8-bit reg"; - return 0; - } -} - -uint8_t set_reg_byte(uint8_t code) { - switch (code) - { +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; @@ -114,4 +105,129 @@ uint8_t set_reg_byte(uint8_t code) { 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; } \ No newline at end of file diff --git a/instructions.h b/instructions.h index 6d14fe7..4a0858e 100644 --- a/instructions.h +++ b/instructions.h @@ -7,4 +7,79 @@ void add_eb_gb() { ModRM modrm = parse_modrm(modrm_byte); uint8_t gb_value = get_reg_byte(modrm.reg); + uint8_t eb_value; + uint32_t eb_addr; + bool eb_is_mem = false; + + if (modrm.mod == 3) { + // eb is a reg + eb_value = get_reg_byte(modrm.rm); + } else { + // eb is an addr + uint32_t eff_addr = calc_effective_addr(modrm); + uint16_t segment = (modrm.rm == 2 || modrm.rm == 3 || modrm.rm == 6) ? SS : DS; + uint32_t phys_addr = physical_addr(segment, eff_addr); + eb_value = ram[phys_addr]; + eb_is_mem = true; + } + + uint8_t result = eb_value + gb_value; + + if (eb_is_mem) { + ram[eb_addr] = result; + } else { + set_reg_byte(modrm.rm, result); + } + + update_flags_add(eb_value, gb_value, result); +} + +void add_ev_gv() { + uint32_t addr = physical_addr(CS, IP); + uint8_t modrm_byte = ram[addr]; + IP ++; + + ModRM modrm = parse_modrm(modrm_byte); + uint16_t gv_value = get_reg_word(modrm.reg); + uint16_t ev_value; + uint32_t ev_addr; + bool ev_is_mem = false; + + if (modrm.mod == 3) { + ev_value = get_reg_word(modrm.rm); + } else { + uint16_t seg = (modrm.rm == 4 || modrm.rm == 5 || modrm.rm == 6) ? SS : DS; + uint16_t eff_addr = calc_effective_addr(modrm); + ev_addr = physical_addr(seg, eff_addr); + + ev_value = ram[ev_addr] | (ram[ev_addr + 1] << 8); + ev_is_mem = true; + } + + uint16_t result = ev_value + gv_value; + + if (ev_is_mem) { + ram[ev_addr] = result & 0xFF; + ram[ev_addr + 1] = result >> 8; + } else { + set_reg_word(modrm.rm, result); + } + + update_flags_add16(ev_value, gv_value, result); + std::cout << "AX = " << std::hex << AX.value + << " (AL=" << (int)AX.low << ")\n"; +} + +void hlt() { + std::cout << "HLT\n"; + exit(0); +} + +using instrHandler = void(*)(); +instrHandler instr_table[256] = { nullptr }; + +void init_instr_table() { + instr_table[0x00] = add_eb_gb; + instr_table[0x01] = add_ev_gv; + instr_table[0xf4] = hlt; } \ No newline at end of file diff --git a/main.cpp b/main.cpp index 622c837..e116ec2 100644 --- a/main.cpp +++ b/main.cpp @@ -4,14 +4,23 @@ void emulate() { while (1) { uint32_t addr = physical_addr(CS, IP); uint8_t opcode = ram[addr]; - + instrHandler handler = instr_table[opcode]; + IP++; + + if (handler) handler(); + else { + std::cout << "unknown opcode " << std::hex << opcode << "\n"; + break; + } } } int main(int argc, char* argv[]) { CS = 0x0000; - IP = 0x0100; + IP = 0x0000; + AX.value = 0x7fff; + BX.value = 0x7fff; if (argc < 2) { std::cerr << "usage: " << argv[0] << "\n"; @@ -23,6 +32,7 @@ int main(int argc, char* argv[]) { return 1; } + init_instr_table(); emulate(); return 0; } \ No newline at end of file