diff --git a/8086_sim/.gitignore b/8086_sim/.gitignore new file mode 100644 index 0000000..b28fd9b --- /dev/null +++ b/8086_sim/.gitignore @@ -0,0 +1,8 @@ +listing_0043_immediate_movs +listing_0044_register_movs +listing_0045_challenge_register_movs +listing_0046_add_sub_cmp +listing_0047_challenge_flags +listing_0048_ip_register +listing_0049_conditional_jumps +listing_0050_challenge_jumps diff --git a/8086_sim/flag_access.cpp b/8086_sim/flag_access.cpp new file mode 100644 index 0000000..ed49cab --- /dev/null +++ b/8086_sim/flag_access.cpp @@ -0,0 +1,57 @@ +#include "include/flag_access.h" +#include "include/aliases.h" +#include + +const char *get_flag_string(flag_access flag); + +static bool flags[FLAG_COUNT] = {false}; + +bool get_flag(flag_access flag) { + if (flag < FLAG_COUNT) { + return flags[flag]; + } + + return false; +} + +void set_flags(u16 value) { + if (value == 0) { + flags[FLAG_ZERO] = true; + flags[FLAG_SIGN] = false; + } else if ((value & 0x8000) == 0x8000) { + flags[FLAG_ZERO] = false; + flags[FLAG_SIGN] = true; + } else { + flags[FLAG_ZERO] = false; + flags[FLAG_SIGN] = false; + } +} + +void print_flags() { + printf("\t"); + + for (u32 i = 0; i < FLAG_COUNT; ++i) { + if (flags[i]) { + printf("%s", get_flag_string((flag_access)i)); + } + } + + printf("\n"); +} + +const char *get_flag_string(flag_access flag) { + const char *output = ""; + + switch (flag) { + case FLAG_ZERO: + output = "Z"; + break; + case FLAG_SIGN: + output = "S"; + break; + default: + break; + } + + return output; +} diff --git a/8086_sim/include/flag_access.h b/8086_sim/include/flag_access.h new file mode 100644 index 0000000..facf825 --- /dev/null +++ b/8086_sim/include/flag_access.h @@ -0,0 +1,17 @@ +#ifndef FLAG_ACCESS_H +#define FLAG_ACCESS_H + +#include "aliases.h" + +enum flag_access : u8 { + FLAG_ZERO, + FLAG_SIGN, + + FLAG_COUNT +}; + +bool get_flag(flag_access flag); +void set_flags(u16 value); +void print_flags(); + +#endif // !FLAG_ACCESS_H diff --git a/8086_sim/listing_0046_add_sub_cmp.asm b/8086_sim/listing_0046_add_sub_cmp.asm new file mode 100644 index 0000000..09f8205 --- /dev/null +++ b/8086_sim/listing_0046_add_sub_cmp.asm @@ -0,0 +1,28 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 46 +; ======================================================================== + +bits 16 + +mov bx, -4093 +mov cx, 3841 +sub bx, cx + +mov sp, 998 +mov bp, 999 +cmp bp, sp + +add bp, 1027 +sub bp, 2026 diff --git a/8086_sim/listing_0047_challenge_flags.asm b/8086_sim/listing_0047_challenge_flags.asm new file mode 100644 index 0000000..f0279f7 --- /dev/null +++ b/8086_sim/listing_0047_challenge_flags.asm @@ -0,0 +1,36 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 47 +; ======================================================================== + +bits 16 + +add bx, 30000 +add bx, 10000 +sub bx, 5000 +sub bx, 5000 + +mov bx, 1 +mov cx, 100 +add bx, cx + +mov dx, 10 +sub cx, dx + +add bx, 40000 +add cx, -90 + +mov sp, 99 +mov bp, 98 +cmp bp, sp diff --git a/8086_sim/listing_0048_ip_register.asm b/8086_sim/listing_0048_ip_register.asm new file mode 100644 index 0000000..af716bd --- /dev/null +++ b/8086_sim/listing_0048_ip_register.asm @@ -0,0 +1,23 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 48 +; ======================================================================== + +bits 16 + +mov cx, 200 +mov bx, cx +add cx, 1000 +mov bx, 2000 +sub cx, bx diff --git a/8086_sim/listing_0049_conditional_jumps.asm b/8086_sim/listing_0049_conditional_jumps.asm new file mode 100644 index 0000000..65112c7 --- /dev/null +++ b/8086_sim/listing_0049_conditional_jumps.asm @@ -0,0 +1,24 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 49 +; ======================================================================== + +bits 16 + +mov cx, 3 +mov bx, 1000 +loop_start: +add bx, 10 +sub cx, 1 +jnz loop_start diff --git a/8086_sim/listing_0050_challenge_jumps.asm b/8086_sim/listing_0050_challenge_jumps.asm new file mode 100644 index 0000000..8d2f484 --- /dev/null +++ b/8086_sim/listing_0050_challenge_jumps.asm @@ -0,0 +1,38 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 50 +; ======================================================================== + +bits 16 + +mov ax, 10 +mov bx, 10 +mov cx, 10 + +label_0: +cmp bx, cx +je label_1 + +add ax, 1 +jp label_2 + +label_1: +sub bx, 5 +jb label_3 + +label_2: +sub cx, 2 + +label_3: +loopnz label_0 diff --git a/8086_sim/sim86 b/8086_sim/sim86 new file mode 100755 index 0000000..89fe10f Binary files /dev/null and b/8086_sim/sim86 differ diff --git a/8086_sim/sim86.cpp b/8086_sim/sim86.cpp index b9e578d..f1b2525 100644 --- a/8086_sim/sim86.cpp +++ b/8086_sim/sim86.cpp @@ -1,11 +1,18 @@ #include "include/aliases.h" +#include "include/flag_access.h" #include "include/reg_access.h" #include "include/sim86_lib.h" #include #include #include -void decode_operand(instruction_operand operand); +struct basic_string { + char str[4096]; +}; + +u16 get_operand_value(instruction_operand operand); +basic_string get_operand_string(instruction_operand operand); +void print_instruction(instruction inst); void mov_to_register(const register_access ®, const instruction_operand &source); @@ -44,6 +51,8 @@ int main(int argc, char *argv[]) { bool accessed_registers[REGISTER_COUNT] = {false}; + printf("\nDisassembly:\n"); + while (offset < size) { instruction decoded; Sim86_Decode8086Instruction(size - offset, buffer + offset, &decoded); @@ -51,46 +60,129 @@ int main(int argc, char *argv[]) { if (decoded.Op) { offset += decoded.Size; - if (decoded.Op == Op_mov) { - instruction_operand dest = decoded.Operands[0]; - instruction_operand source = decoded.Operands[1]; + print_instruction(decoded); + + instruction_operand dest = decoded.Operands[0]; + instruction_operand source = decoded.Operands[1]; + + switch (decoded.Op) { + case Op_mov: { if (dest.Type == Operand_Register) { mov_to_register(dest.Register, source); accessed_registers[dest.Register.Index] = true; } + + break; + } + case Op_add: { + if (dest.Type == Operand_Register) { + u16 value = get_register(dest.Register); + + value += get_operand_value(source); + set_flags(value); + + set_register(dest.Register, value); + } + + break; + } + case Op_sub: + case Op_cmp: { + if (dest.Type == Operand_Register) { + u16 value = get_register(dest.Register); + + value -= get_operand_value(source); + set_flags(value); + + if (decoded.Op == Op_sub) { + set_register(dest.Register, value); + } + } + + break; + } + case Op_jne: { + if (!get_flag(FLAG_ZERO)) { + i16 inst_offset = get_operand_value(dest); + + offset += inst_offset; + } + } + default: + break; } } } + printf("\nFinal registers:\n"); + for (u32 i = 0; i < REGISTER_COUNT; ++i) { if (accessed_registers[i]) { register_access reg = {i, 0, 2}; u16 value = get_register(reg); - printf("%s: 0x%04x (%d)\n", get_register_name(reg), value, value); + printf("\t%s: 0x%04x (%d)\n", get_register_name(reg), value, value); } } + // Print the instruction pointer register + printf("\tip: 0x%04x (%d)\n", offset, offset); + + printf("\nFinal flags:\n"); + print_flags(); + return 0; } -void decode_operand(instruction_operand operand) { +u16 get_operand_value(instruction_operand operand) { switch (operand.Type) { case Operand_Register: - printf("Register operand: %d, %d, %d\n", operand.Register.Index, - operand.Register.Offset, operand.Register.Count); + return get_register(operand.Register); + break; case Operand_Memory: - // printf("Memory operand\n"); + return 0; + break; case Operand_Immediate: - // printf("Immediate operand\n"); + return operand.Immediate.Value; + + break; + default: + return 0; + break; + } +} + +basic_string get_operand_string(instruction_operand operand) { + basic_string output = {""}; + + switch (operand.Type) { + case Operand_Register: + sprintf(output.str, "%s", get_register_name(operand.Register)); + + break; + case Operand_Memory: + sprintf(output.str, "%s", "MEM OPERAND"); + + break; + case Operand_Immediate: + sprintf(output.str, "%d", operand.Immediate.Value); + break; default: break; } + + return output; +} + +void print_instruction(instruction inst) { + printf("\t%s %s, %s\n", Sim86_MnemonicFromOperationType(inst.Op), + get_operand_string(inst.Operands[0]).str, + get_operand_string(inst.Operands[1]).str); } void mov_to_register(const register_access ®,