diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index ac8a2a8..d722921 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -15,7 +15,7 @@ "windowsSdkVersion": "10.0.22000.0", "compilerPath": "C:/MinGW/bin/gcc.exe", "cStandard": "c17", - "cppStandard": "c++17", + "cppStandard": "c++11", "intelliSenseMode": "windows-gcc-x86", "configurationProvider": "ms-vscode.makefile-tools" } diff --git a/examples/immediate_movs.asm b/examples/immediate_movs.asm new file mode 100644 index 0000000..c706ce7 --- /dev/null +++ b/examples/immediate_movs.asm @@ -0,0 +1,27 @@ +; ======================================================================== +; +; (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 43 +; ======================================================================== + +bits 16 + +mov ax, 1 +mov bx, 2 +mov cx, 3 +mov dx, 4 + +mov sp, 5 +mov bp, 6 +mov si, 7 +mov di, 8 \ No newline at end of file diff --git a/examples/immediate_movs.txt b/examples/immediate_movs.txt new file mode 100644 index 0000000..16a7a97 --- /dev/null +++ b/examples/immediate_movs.txt @@ -0,0 +1,19 @@ +--- test\listing_0043_immediate_movs execution --- +mov ax, 1 ; ax:0x0->0x1 +mov bx, 2 ; bx:0x0->0x2 +mov cx, 3 ; cx:0x0->0x3 +mov dx, 4 ; dx:0x0->0x4 +mov sp, 5 ; sp:0x0->0x5 +mov bp, 6 ; bp:0x0->0x6 +mov si, 7 ; si:0x0->0x7 +mov di, 8 ; di:0x0->0x8 + +Final registers: + ax: 0x0001 (1) + bx: 0x0002 (2) + cx: 0x0003 (3) + dx: 0x0004 (4) + sp: 0x0005 (5) + bp: 0x0006 (6) + si: 0x0007 (7) + di: 0x0008 (8) \ No newline at end of file diff --git a/examples/register_movs.asm b/examples/register_movs.asm new file mode 100644 index 0000000..4400687 --- /dev/null +++ b/examples/register_movs.asm @@ -0,0 +1,32 @@ +; ======================================================================== +; +; (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 44 +; ======================================================================== + +bits 16 + +mov ax, 1 +mov bx, 2 +mov cx, 3 +mov dx, 4 + +mov sp, ax +mov bp, bx +mov si, cx +mov di, dx + +mov dx, sp +mov cx, bp +mov bx, si +mov ax, di \ No newline at end of file diff --git a/examples/register_movs.txt b/examples/register_movs.txt new file mode 100644 index 0000000..aef16bd --- /dev/null +++ b/examples/register_movs.txt @@ -0,0 +1,23 @@ +--- test\listing_0044_register_movs execution --- +mov ax, 1 ; ax:0x0->0x1 +mov bx, 2 ; bx:0x0->0x2 +mov cx, 3 ; cx:0x0->0x3 +mov dx, 4 ; dx:0x0->0x4 +mov sp, ax ; sp:0x0->0x1 +mov bp, bx ; bp:0x0->0x2 +mov si, cx ; si:0x0->0x3 +mov di, dx ; di:0x0->0x4 +mov dx, sp ; dx:0x4->0x1 +mov cx, bp ; cx:0x3->0x2 +mov bx, si ; bx:0x2->0x3 +mov ax, di ; ax:0x1->0x4 + +Final registers: + ax: 0x0004 (4) + bx: 0x0003 (3) + cx: 0x0002 (2) + dx: 0x0001 (1) + sp: 0x0001 (1) + bp: 0x0002 (2) + si: 0x0003 (3) + di: 0x0004 (4) diff --git a/src/main.c b/src/main.c index dfc9563..227d935 100644 --- a/src/main.c +++ b/src/main.c @@ -107,7 +107,29 @@ int dissassemble(FILE *src, FILE *dst) { } int simulate(FILE *src) { - todo("simulate"); + struct cpu_state state = { 0 }; + struct instruction inst; + int counter = 1; + while (true) { + enum decode_error err = decode_instruction(src, &inst); + if (err == DECODE_ERR_EOF) break; + if (err != DECODE_OK) { + fprintf(stderr, "ERROR: Failed to decode %d instruction: %s\n", counter, decode_error_to_str(err)); + return -1; + } + execute_instruction(&state, &inst); + counter += 1; + } + + printf("Final registers:\n"); + printf(" ax: 0x%04x (%d)\n", state.ax, state.ax); + printf(" bx: 0x%04x (%d)\n", state.bx, state.bx); + printf(" cx: 0x%04x (%d)\n", state.cx, state.cx); + printf(" sp: 0x%04x (%d)\n", state.sp, state.sp); + 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); + return 0; } void print_usage(const char *program) { diff --git a/src/sim8086.h b/src/sim8086.h index 571bf0a..af51683 100644 --- a/src/sim8086.h +++ b/src/sim8086.h @@ -99,4 +99,15 @@ struct instruction { struct reg_or_mem_value dest; struct src_value src; i8 jmp_offset; +}; + +struct cpu_state { + u16 ax; + u16 bx; + u16 cx; + u16 dx; + u16 sp; + u16 bp; + u16 si; + u16 di; }; \ No newline at end of file diff --git a/src/sim8086_decoder.c b/src/sim8086_decoder.c index b1d81c2..d14b56c 100644 --- a/src/sim8086_decoder.c +++ b/src/sim8086_decoder.c @@ -114,6 +114,7 @@ static void deocde_reg_or_mem_to_src(struct src_value *value, FILE *src, u8 rm, } } +// TODO: change to readinf from a byte buffer // TODO: add handling for 'DECODE_ERR_MISSING_BYTES' // Handy reference: Table 4-12. 8086 Instruction Encoding enum decode_error decode_instruction(FILE *src, struct instruction *output) { diff --git a/src/sim8086_simulator.c b/src/sim8086_simulator.c index e69de29..c086bd8 100644 --- a/src/sim8086_simulator.c +++ b/src/sim8086_simulator.c @@ -0,0 +1,106 @@ + +u16 get_register_value(struct cpu_state *state, enum reg_value reg) +{ + switch (reg) + { + case REG_AL: return state->ax & 0xFF; + case REG_CL: return state->cx & 0xFF; + case REG_DL: return state->dx & 0xFF; + case REG_BL: return state->bx & 0xFF; + case REG_AH: return (state->ax >> 8) & 0xFF; + case REG_CH: return (state->cx >> 8) & 0xFF; + case REG_DH: return (state->dx >> 8) & 0xFF; + case REG_BH: return (state->bx >> 8) & 0xFF; + case REG_AX: return state->ax; + case REG_CX: return state->cx; + case REG_DX: return state->dx; + case REG_BX: return state->bx; + case REG_SP: return state->sp; + case REG_BP: return state->bp; + case REG_SI: return state->si; + case REG_DI: return state->di; + default: panic("Unhandled register '%s'", reg_to_str(reg)); + } +} + +void set_register_value(struct cpu_state *state, enum reg_value reg, u16 value) +{ + switch (reg) + { + case REG_AL: + state->ax = (state->ax & 0xFF00) & value; + break; + case REG_CL: + state->cx = (state->cx & 0xFF00) & value; + break; + case REG_DL: + state->dx = (state->dx & 0xFF00) & value; + break; + case REG_BL: + state->bx = (state->bx & 0xFF00) & value; + break; + case REG_AH: + state->ax = (state->ax & 0x00FF) & (value << 8); + break; + case REG_CH: + state->cx = (state->cx & 0x00FF) & (value << 8); + break; + case REG_DH: + state->dx = (state->dx & 0x00FF) & (value << 8); + break; + case REG_BH: + state->bx = (state->bx & 0x00FF) & (value << 8); + break; + case REG_AX: + state->ax = value; + break; + case REG_CX: + state->cx = value; + break; + case REG_DX: + state->dx = value; + break; + case REG_BX: + state->bx = value; + break; + case REG_SP: + state->sp = value; + break; + case REG_BP: + state->bp = value; + break; + case REG_SI: + state->si = value; + break; + case REG_DI: + state->di = value; + break; + default: + panic("Unhandled register '%s'", reg_to_str(reg)); + } +} + +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); + break; + default: + todo("Unhandled instruction execution '%s'\n", operation_to_str(inst->op)); + } +} \ No newline at end of file