From 2900e508a1466e06a5b9ddd49c2b24be99f8c8e0 Mon Sep 17 00:00:00 2001 From: Abdelrahman Said Date: Sun, 16 Apr 2023 14:29:54 -0700 Subject: [PATCH] Completed homework for 8086 simulator --- 8086_sim/.gitignore | 7 + 8086_sim/listing_0051_memory_mov.asm | 30 +++ 8086_sim/listing_0052_memory_add_loop.asm | 36 ++++ 8086_sim/listing_0053_add_loop_challenge.asm | 35 ++++ 8086_sim/listing_0054_draw_rectangle.asm | 43 ++++ 8086_sim/sim86.cpp | 204 ++++++++++++++++--- 6 files changed, 330 insertions(+), 25 deletions(-) create mode 100644 8086_sim/listing_0051_memory_mov.asm create mode 100644 8086_sim/listing_0052_memory_add_loop.asm create mode 100644 8086_sim/listing_0053_add_loop_challenge.asm create mode 100644 8086_sim/listing_0054_draw_rectangle.asm diff --git a/8086_sim/.gitignore b/8086_sim/.gitignore index 0916687..9666394 100644 --- a/8086_sim/.gitignore +++ b/8086_sim/.gitignore @@ -7,3 +7,10 @@ listing_0047_challenge_flags listing_0048_ip_register listing_0049_conditional_jumps listing_0050_challenge_jumps +listing_0051_memory_mov +listing_0052_memory_add_loop +listing_0053_add_loop_challenge +listing_0054_draw_rectangle +test.asm +test +image.data diff --git a/8086_sim/listing_0051_memory_mov.asm b/8086_sim/listing_0051_memory_mov.asm new file mode 100644 index 0000000..5bd58de --- /dev/null +++ b/8086_sim/listing_0051_memory_mov.asm @@ -0,0 +1,30 @@ +; ======================================================================== +; +; (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 51 +; ======================================================================== + +bits 16 + +mov word [1000], 1 +mov word [1002], 2 +mov word [1004], 3 +mov word [1006], 4 + +mov bx, 1000 +mov word [bx + 4], 10 + +mov bx, word [1000] +mov cx, word [1002] +mov dx, word [1004] +mov bp, word [1006] diff --git a/8086_sim/listing_0052_memory_add_loop.asm b/8086_sim/listing_0052_memory_add_loop.asm new file mode 100644 index 0000000..de5ceb8 --- /dev/null +++ b/8086_sim/listing_0052_memory_add_loop.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 52 +; ======================================================================== + +bits 16 + +mov dx, 6 +mov bp, 1000 + +mov si, 0 +init_loop_start: + mov word [bp + si], si + add si, 2 + cmp si, dx + jnz init_loop_start + +mov bx, 0 +mov si, 0 +add_loop_start: + mov cx, word [bp + si] + add bx, cx + add si, 2 + cmp si, dx + jnz add_loop_start diff --git a/8086_sim/listing_0053_add_loop_challenge.asm b/8086_sim/listing_0053_add_loop_challenge.asm new file mode 100644 index 0000000..ae7bca4 --- /dev/null +++ b/8086_sim/listing_0053_add_loop_challenge.asm @@ -0,0 +1,35 @@ +; ======================================================================== +; +; (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 53 +; ======================================================================== + +bits 16 + +mov dx, 6 +mov bp, 1000 + +mov si, 0 +init_loop_start: + mov word [bp + si], si + add si, 2 + cmp si, dx + jnz init_loop_start + +mov bx, 0 +mov si, dx +sub bp, 2 +add_loop_start: + add bx, word [bp + si] + sub si, 2 + jnz add_loop_start diff --git a/8086_sim/listing_0054_draw_rectangle.asm b/8086_sim/listing_0054_draw_rectangle.asm new file mode 100644 index 0000000..5bf516a --- /dev/null +++ b/8086_sim/listing_0054_draw_rectangle.asm @@ -0,0 +1,43 @@ +; ======================================================================== +; +; (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 54 +; ======================================================================== + +bits 16 + +; Start image after one row, to avoid overwriting our code! +mov bp, 64*4 + +mov dx, 0 +y_loop_start: + + mov cx, 0 + x_loop_start: + ; Fill pixel + mov word [bp + 0], cx ; Red + mov word [bp + 2], dx ; Blue + mov byte [bp + 3], 255 ; Alpha + + ; Advance pixel location + add bp, 4 + + ; Advance X coordinate and loop + add cx, 1 + cmp cx, 64 + jnz x_loop_start + + ; Advance Y coordinate and loop + add dx, 1 + cmp dx, 64 + jnz y_loop_start diff --git a/8086_sim/sim86.cpp b/8086_sim/sim86.cpp index 5a57241..b0dade6 100644 --- a/8086_sim/sim86.cpp +++ b/8086_sim/sim86.cpp @@ -1,22 +1,43 @@ #include "include/aliases.h" #include "include/flag_access.h" #include "include/reg_access.h" +#include "include/sim86_instruction.h" #include "include/sim86_lib.h" #include #include #include #define MEM_SIZE (1 << 16) +#define BITS_PER_BYTE 8 struct basic_string { char str[4096]; }; -u16 get_operand_value(instruction_operand operand); -basic_string get_operand_string(instruction_operand operand); +struct membuf { + u8 buffer[MEM_SIZE]; + u64 mem_start; +}; + +struct mem_access_result { + u16 value; + u32 error; +}; + +u16 get_operand_value(instruction_operand operand, bool wide); +basic_string get_operand_string(instruction_operand operand, bool wide); void print_instruction(instruction inst); void mov_to_register(const register_access ®, - const instruction_operand &source); + const instruction_operand &source, bool wide); +void mov_to_memory(const effective_address_expression &addrexp, + const instruction_operand &source, bool wide); +mem_access_result get_mem_value(const effective_address_expression &addrexp, + bool wide); +mem_access_result set_mem_value(const effective_address_expression &addrexp, + u16 value, bool wide); +u16 get_mem_index(const effective_address_expression &addrexp); + +static membuf memory; int main(int argc, char *argv[]) { if (argc < 2) { @@ -24,8 +45,8 @@ int main(int argc, char *argv[]) { return 1; } - u8 memory[MEM_SIZE]; - memset((void *)memory, 0, MEM_SIZE); + memset((void *)memory.buffer, 0, MEM_SIZE); + memory.mem_start = 0; const char *filename = argv[1]; @@ -42,14 +63,14 @@ int main(int argc, char *argv[]) { fseek(fp, 0, SEEK_SET); - fread((void *)memory, sizeof(u8), size, fp); + fread((void *)memory.buffer, sizeof(u8), size, fp); + memory.mem_start = size + 1; fclose(fp); instruction_table table; Sim86_Get8086InstructionTable(&table); - u32 mem_start = size + 1; u32 offset = 0; bool accessed_registers[REGISTER_COUNT] = {false}; @@ -58,10 +79,12 @@ int main(int argc, char *argv[]) { while (offset < size) { instruction decoded; - Sim86_Decode8086Instruction(size - offset, memory + offset, &decoded); + Sim86_Decode8086Instruction(size - offset, memory.buffer + offset, + &decoded); if (decoded.Op) { offset += decoded.Size; + bool wide = (decoded.Flags & Inst_Wide) == Inst_Wide; print_instruction(decoded); @@ -70,11 +93,12 @@ int main(int argc, char *argv[]) { switch (decoded.Op) { case Op_mov: { - if (dest.Type == Operand_Register) { - mov_to_register(dest.Register, source); + mov_to_register(dest.Register, source, wide); accessed_registers[dest.Register.Index] = true; + } else if (dest.Type == Operand_Memory) { + mov_to_memory(dest.Address, source, wide); } break; @@ -83,7 +107,7 @@ int main(int argc, char *argv[]) { if (dest.Type == Operand_Register) { u16 value = get_register(dest.Register); - value += get_operand_value(source); + value += get_operand_value(source, wide); set_flags(value); set_register(dest.Register, value); @@ -96,7 +120,7 @@ int main(int argc, char *argv[]) { if (dest.Type == Operand_Register) { u16 value = get_register(dest.Register); - value -= get_operand_value(source); + value -= get_operand_value(source, wide); set_flags(value); if (decoded.Op == Op_sub) { @@ -108,7 +132,7 @@ int main(int argc, char *argv[]) { } case Op_jne: { if (!get_flag(FLAG_ZERO)) { - i16 inst_offset = get_operand_value(dest); + i16 inst_offset = get_operand_value(dest, wide); offset += inst_offset; } @@ -136,30 +160,54 @@ int main(int argc, char *argv[]) { printf("\nFinal flags:\n"); print_flags(); +#if 0 // Only needed (and working) for listing 0054 +#define SIZE 64 +#define BYTES SIZE * 4 * SIZE + + u8 image[BYTES]; + mempcpy(image, &(memory.buffer[memory.mem_start + (SIZE * 4)]), BYTES); + + FILE *out = fopen("image.data", "wb"); + + fwrite(image, sizeof(u8), BYTES, out); + + fclose(out); +#endif + return 0; } -u16 get_operand_value(instruction_operand operand) { +u16 get_operand_value(instruction_operand operand, bool wide) { + u16 output = 0; + switch (operand.Type) { case Operand_Register: - return get_register(operand.Register); + output = get_register(operand.Register); break; - case Operand_Memory: - return 0; + case Operand_Memory: { + mem_access_result result = get_mem_value(operand.Address, wide); + + if (result.error) { + break; + } + + output = result.value; break; + } case Operand_Immediate: - return operand.Immediate.Value; + output = operand.Immediate.Value; break; default: - return 0; break; } + + return output; } -basic_string get_operand_string(instruction_operand operand) { +basic_string get_operand_string(instruction_operand operand, bool wide) { basic_string output = {""}; switch (operand.Type) { @@ -167,10 +215,27 @@ basic_string get_operand_string(instruction_operand operand) { sprintf(output.str, "%s", get_register_name(operand.Register)); break; - case Operand_Memory: - sprintf(output.str, "%s", "MEM OPERAND"); + case Operand_Memory: { + char mem_string[1024] = {0}; + + register_access reg1 = operand.Address.Terms[0].Register; + if (reg1.Index != 0) { + sprintf(mem_string, "%s + ", get_register_name(reg1)); + } + + register_access reg2 = operand.Address.Terms[1].Register; + if (reg2.Index != 0) { + strcat(mem_string, get_register_name(reg2)); + } else { + u32 length = strlen(mem_string); + + sprintf(&(mem_string[length]), "%d", operand.Address.Displacement); + } + + sprintf(output.str, "%s [%s]", wide ? "word" : "byte", mem_string); break; + } case Operand_Immediate: sprintf(output.str, "%d", operand.Immediate.Value); @@ -183,13 +248,15 @@ basic_string get_operand_string(instruction_operand operand) { } void print_instruction(instruction inst) { + bool wide = (inst.Flags & Inst_Wide) == Inst_Wide; + printf("\t%s %s, %s\n", Sim86_MnemonicFromOperationType(inst.Op), - get_operand_string(inst.Operands[0]).str, - get_operand_string(inst.Operands[1]).str); + get_operand_string(inst.Operands[0], wide).str, + get_operand_string(inst.Operands[1], wide).str); } void mov_to_register(const register_access ®, - const instruction_operand &source) { + const instruction_operand &source, bool wide) { switch (source.Type) { case Operand_Immediate: set_register(reg, source.Immediate.Value); @@ -197,7 +264,94 @@ void mov_to_register(const register_access ®, case Operand_Register: set_register(reg, get_register(source.Register)); break; + case Operand_Memory: { + mem_access_result result = get_mem_value(source.Address, wide); + + if (!result.error) { + set_register(reg, result.value); + } + + break; + } default: break; } } + +void mov_to_memory(const effective_address_expression &addrexp, + const instruction_operand &source, bool wide) { + switch (source.Type) { + case Operand_Immediate: + set_mem_value(addrexp, source.Immediate.Value, wide); + break; + case Operand_Register: + set_mem_value(addrexp, get_register(source.Register), wide); + break; + case Operand_Memory: { + mem_access_result result = get_mem_value(source.Address, wide); + + if (!result.error) { + set_mem_value(addrexp, result.value, wide); + } + + break; + } + default: + break; + } +} + +mem_access_result get_mem_value(const effective_address_expression &addrexp, + bool wide) { + u16 index = get_mem_index(addrexp); + + mem_access_result result = {0, 0}; + + if (memory.mem_start + index >= MEM_SIZE) { + result.error = 1; + } else { + result.value |= memory.buffer[memory.mem_start + index]; + + if (wide) { + result.value |= (memory.buffer[memory.mem_start + index + 1] + << (wide ? BITS_PER_BYTE : 0)); + } + } + + return result; +} + +mem_access_result set_mem_value(const effective_address_expression &addrexp, + u16 value, bool wide) { + u16 index = get_mem_index(addrexp); + + mem_access_result result = {0, 0}; + + if (memory.mem_start + index >= MEM_SIZE) { + result.error = 1; + } else { + memory.buffer[memory.mem_start + index] = (u8)value; + + if (wide) { + memory.buffer[memory.mem_start + index + 1] = + (u8)(value >> (wide ? BITS_PER_BYTE : 0)); + } + + result.value = value; + } + + return result; +} + +u16 get_mem_index(const effective_address_expression &addrexp) { + u16 index = addrexp.Displacement; + + const u16 term_count = 2; + for (u16 i = 0; i < term_count; ++i) { + if (addrexp.Terms[i].Register.Index != 0) { + index += get_register(addrexp.Terms[i].Register); + } + } + + return index; +}