From 5ba1f1f948e5ed9794243fbd8e1c9c159e32447c Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Mon, 24 Apr 2023 23:06:34 +0300 Subject: [PATCH] simulate add, sub and cmp --- examples/add_sub_cmp.asm | 28 +++++++++ examples/add_sub_cmp.txt | 15 +++++ src/main.c | 1 + src/sim8086.h | 6 ++ src/sim8086_simulator.c | 132 +++++++++++++++++++++++++++++++++------ 5 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 examples/add_sub_cmp.asm create mode 100644 examples/add_sub_cmp.txt diff --git a/examples/add_sub_cmp.asm b/examples/add_sub_cmp.asm new file mode 100644 index 0000000..09f8205 --- /dev/null +++ b/examples/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/examples/add_sub_cmp.txt b/examples/add_sub_cmp.txt new file mode 100644 index 0000000..509aa24 --- /dev/null +++ b/examples/add_sub_cmp.txt @@ -0,0 +1,15 @@ +--- test\listing_0046_add_sub_cmp execution --- +mov bx, 61443 ; bx:0x0->0xf003 +mov cx, 3841 ; cx:0x0->0xf01 +sub bx, cx ; bx:0xf003->0xe102 flags:->S +mov sp, 998 ; sp:0x0->0x3e6 +mov bp, 999 ; bp:0x0->0x3e7 +cmp bp, sp ; flags:S-> +add bp, 1027 ; bp:0x3e7->0x7ea +sub bp, 2026 ; bp:0x7ea->0x0 flags:->PZ + +Final registers: + bx: 0xe102 (57602) + cx: 0x0f01 (3841) + sp: 0x03e6 (998) + flags: PZ diff --git a/src/main.c b/src/main.c index 227d935..ddd659d 100644 --- a/src/main.c +++ b/src/main.c @@ -129,6 +129,7 @@ int simulate(FILE *src) { printf(" bp: 0x%04x (%d)\n", state.bp, state.bp); printf(" si: 0x%04x (%d)\n", state.si, state.si); printf(" di: 0x%04x (%d)\n", state.di, state.di); + printf(" flags: %s%s\n", state.flags.sign ? "S" : "", state.flags.zero ? "Z" : ""); return 0; } diff --git a/src/sim8086.h b/src/sim8086.h index af51683..b33c6b3 100644 --- a/src/sim8086.h +++ b/src/sim8086.h @@ -110,4 +110,10 @@ struct cpu_state { u16 bp; u16 si; u16 di; + + struct { + bool zero; + bool sign; + // TODO: Add all flags + } flags; }; \ No newline at end of file diff --git a/src/sim8086_simulator.c b/src/sim8086_simulator.c index c086bd8..ab99040 100644 --- a/src/sim8086_simulator.c +++ b/src/sim8086_simulator.c @@ -1,5 +1,5 @@ -u16 get_register_value(struct cpu_state *state, enum reg_value reg) +u16 read_reg_value(struct cpu_state *state, enum reg_value reg) { switch (reg) { @@ -23,7 +23,7 @@ u16 get_register_value(struct cpu_state *state, enum reg_value reg) } } -void set_register_value(struct cpu_state *state, enum reg_value reg, u16 value) +void write_reg_value(struct cpu_state *state, enum reg_value reg, u16 value) { switch (reg) { @@ -80,26 +80,122 @@ void set_register_value(struct cpu_state *state, enum reg_value reg, u16 value) } } +u16 read_src_value(struct cpu_state *state, struct src_value *src) { + switch (src->variant) + { + case SRC_VALUE_REG: + return read_reg_value(state, src->reg); + case SRC_VALUE_IMMEDIATE8: + case SRC_VALUE_IMMEDIATE16: + return src->immediate; + case SRC_VALUE_MEM: + todo("Handle read from memory"); + default: + panic("Unhandled src variant %d\n", src->variant); + } +} + +u16 read_src_or_mem_value(struct cpu_state *state, struct reg_or_mem_value *reg_or_mem) { + if (reg_or_mem->is_reg) { + return read_reg_value(state, reg_or_mem->reg); + } else { + todo("Handle read from memory"); + } +} +void write_src_or_mem_value(struct cpu_state *state, struct reg_or_mem_value *reg_or_mem, u16 value) { + if (reg_or_mem->is_reg) { + write_reg_value(state, reg_or_mem->reg, value); + } else { + todo("Handle write to memory"); + } +} + +bool is_reg_16bit(enum reg_value reg) { + switch (reg) + { + case REG_AL: + case REG_CL: + case REG_DL: + case REG_BL: + case REG_AH: + case REG_CH: + case REG_DH: + case REG_BH: + return false; + case REG_AX: + case REG_CX: + case REG_DX: + case REG_BX: + case REG_SP: + case REG_BP: + case REG_SI: + case REG_DI: + return true; + default: panic("Unhandled register '%s'", reg_to_str(reg)); + } +} + +bool are_instruction_operands_16bit(struct instruction *inst) { + if (inst->dest.is_reg) { + return is_reg_16bit(inst->dest.reg); + } else if (inst->src.variant == SRC_VALUE_REG) { + return is_reg_16bit(inst->src.reg); + } else { + return inst->src.variant == SRC_VALUE_IMMEDIATE16; + } +} + void execute_instruction(struct cpu_state *state, struct instruction *inst) { switch (inst->op) { - case OP_MOV: - if (!inst->dest.is_reg) { - todo("Handle MOV to memory"); - } - if (inst->src.variant == SRC_VALUE_MEM) { - todo("Handle MOV from memory"); - } - - u16 src_value; - if (inst->src.variant == SRC_VALUE_REG) { - src_value = get_register_value(state, inst->src.reg); - } else if (inst->src.variant == SRC_VALUE_IMMEDIATE8 || inst->src.variant == SRC_VALUE_IMMEDIATE16) { - src_value = inst->src.immediate; - } - - set_register_value(state, inst->dest.reg, src_value); + case OP_MOV: { + u16 src_value = read_src_value(state, &inst->src); + write_src_or_mem_value(state, &inst->dest, src_value); break; + } + case OP_ADD: { + u16 dest_value = read_src_or_mem_value(state, &inst->dest); + u16 src_value = read_src_value(state, &inst->src); + u16 result = dest_value + src_value; + + state->flags.zero = result == 0; + if (are_instruction_operands_16bit(inst)) { + state->flags.sign = (result >> 15) & 0b1; + } else { + state->flags.sign = (result >> 7) & 0b1; + } + + write_src_or_mem_value(state, &inst->dest, result); + break; + } + case OP_SUB: { + u16 dest_value = read_src_or_mem_value(state, &inst->dest); + u16 src_value = read_src_value(state, &inst->src); + u16 result = dest_value - src_value; + + state->flags.zero = result == 0; + if (are_instruction_operands_16bit(inst)) { + state->flags.sign = (result >> 15) & 0b1; + } else { + state->flags.sign = (result >> 7) & 0b1; + } + + write_src_or_mem_value(state, &inst->dest, result); + break; + } + case OP_CMP: { + u16 dest_value = read_src_or_mem_value(state, &inst->dest); + u16 src_value = read_src_value(state, &inst->src); + u16 result = dest_value - src_value; + + state->flags.zero = result == 0; + if (are_instruction_operands_16bit(inst)) { + state->flags.sign = (result >> 15) & 0b1; + } else { + state->flags.sign = (result >> 7) & 0b1; + } + break; + } default: todo("Unhandled instruction execution '%s'\n", operation_to_str(inst->op)); }