added add_eb_gb and add_ev_gv instructions, fixed some stuff ig
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
emulator
|
emulator
|
||||||
pizda
|
pizda
|
||||||
|
.vscode/*
|
158
emulator.h
158
emulator.h
@@ -41,7 +41,16 @@ bool load_binary(char* filename, size_t addr);
|
|||||||
ModRM parse_modrm(uint8_t byte);
|
ModRM parse_modrm(uint8_t byte);
|
||||||
|
|
||||||
uint8_t get_reg_byte(uint8_t code);
|
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) {
|
uint32_t physical_addr(uint16_t seg, uint16_t offset) {
|
||||||
return ((uint32_t) seg << 4) + offset;
|
return ((uint32_t) seg << 4) + offset;
|
||||||
@@ -82,26 +91,8 @@ ModRM parse_modrm(uint8_t byte) {
|
|||||||
return modrm;
|
return modrm;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t get_reg_byte(uint8_t code, uint8_t value) {
|
uint8_t get_reg_byte(uint8_t code) {
|
||||||
switch (code)
|
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)
|
|
||||||
{
|
|
||||||
case 0: return AX.low;
|
case 0: return AX.low;
|
||||||
case 1: return CX.low;
|
case 1: return CX.low;
|
||||||
case 2: return DX.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";
|
std::cerr << "invalid reg code for 8-bit reg";
|
||||||
return 0;
|
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<int8_t>(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<uint16_t>(b1) + static_cast<uint16_t>(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<uint32_t>(w1) + static_cast<uint32_t>(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;
|
||||||
}
|
}
|
@@ -7,4 +7,79 @@ void add_eb_gb() {
|
|||||||
|
|
||||||
ModRM modrm = parse_modrm(modrm_byte);
|
ModRM modrm = parse_modrm(modrm_byte);
|
||||||
uint8_t gb_value = get_reg_byte(modrm.reg);
|
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;
|
||||||
}
|
}
|
14
main.cpp
14
main.cpp
@@ -4,14 +4,23 @@ void emulate() {
|
|||||||
while (1) {
|
while (1) {
|
||||||
uint32_t addr = physical_addr(CS, IP);
|
uint32_t addr = physical_addr(CS, IP);
|
||||||
uint8_t opcode = ram[addr];
|
uint8_t opcode = ram[addr];
|
||||||
|
instrHandler handler = instr_table[opcode];
|
||||||
|
|
||||||
IP++;
|
IP++;
|
||||||
|
|
||||||
|
if (handler) handler();
|
||||||
|
else {
|
||||||
|
std::cout << "unknown opcode " << std::hex << opcode << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
CS = 0x0000;
|
CS = 0x0000;
|
||||||
IP = 0x0100;
|
IP = 0x0000;
|
||||||
|
AX.value = 0x7fff;
|
||||||
|
BX.value = 0x7fff;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
std::cerr << "usage: " << argv[0] << "<filename>\n";
|
std::cerr << "usage: " << argv[0] << "<filename>\n";
|
||||||
@@ -23,6 +32,7 @@ int main(int argc, char* argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init_instr_table();
|
||||||
emulate();
|
emulate();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Reference in New Issue
Block a user