From 91d8bbcc3df86efe16a6e44527950673138b7e70 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 7 May 2023 15:45:09 +0300 Subject: [PATCH] add simulating writing to memory --- README.md | 6 +- examples/51_memory_mov.asm | 30 +++++ examples/51_memory_mov.txt | 18 +++ examples/52_memory_add_loop.asm | 36 ++++++ examples/52_memory_add_loop.txt | 42 +++++++ src/main.c | 3 +- src/sim8086.c | 6 +- src/sim8086.h | 1 + src/sim8086_decoder.c | 49 ++++---- src/sim8086_memory.c | 25 +++- src/sim8086_simulator.c | 209 +++++++++++++++++++------------- 11 files changed, 305 insertions(+), 120 deletions(-) create mode 100644 examples/51_memory_mov.asm create mode 100644 examples/51_memory_mov.txt create mode 100644 examples/52_memory_add_loop.asm create mode 100644 examples/52_memory_add_loop.txt diff --git a/README.md b/README.md index 3298e19..cbd804d 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,8 @@ For [Computer, Enhance!](https://www.computerenhance.com/) Examples gotten from: https://github.com/cmuratori/computer_enhance/tree/main/perfaware/part1 -Reference: https://edge.edx.org/c4x/BITSPilani/EEE231/asset/8086_family_Users_Manual_1_.pdf \ No newline at end of file +8086 reference manual: https://edge.edx.org/c4x/BITSPilani/EEE231/asset/8086_family_Users_Manual_1_.pdf +Important pages in manual: +* Registers - 24 +* Instruction structures - 163 +* Memory addressing - 83 \ No newline at end of file diff --git a/examples/51_memory_mov.asm b/examples/51_memory_mov.asm new file mode 100644 index 0000000..663f0dd --- /dev/null +++ b/examples/51_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] \ No newline at end of file diff --git a/examples/51_memory_mov.txt b/examples/51_memory_mov.txt new file mode 100644 index 0000000..3210d7d --- /dev/null +++ b/examples/51_memory_mov.txt @@ -0,0 +1,18 @@ +--- test\listing_0051_memory_mov execution --- +mov word [+1000], 1 ; ip:0x0->0x6 +mov word [+1002], 2 ; ip:0x6->0xc +mov word [+1004], 3 ; ip:0xc->0x12 +mov word [+1006], 4 ; ip:0x12->0x18 +mov bx, 1000 ; bx:0x0->0x3e8 ip:0x18->0x1b +mov word [bx+4], 10 ; ip:0x1b->0x20 +mov bx, [+1000] ; bx:0x3e8->0x1 ip:0x20->0x24 +mov cx, [+1002] ; cx:0x0->0x2 ip:0x24->0x28 +mov dx, [+1004] ; dx:0x0->0xa ip:0x28->0x2c +mov bp, [+1006] ; bp:0x0->0x4 ip:0x2c->0x30 + +Final registers: + bx: 0x0001 (1) + cx: 0x0002 (2) + dx: 0x000a (10) + bp: 0x0004 (4) + ip: 0x0030 (48) diff --git a/examples/52_memory_add_loop.asm b/examples/52_memory_add_loop.asm new file mode 100644 index 0000000..65ba3a2 --- /dev/null +++ b/examples/52_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 \ No newline at end of file diff --git a/examples/52_memory_add_loop.txt b/examples/52_memory_add_loop.txt new file mode 100644 index 0000000..c8d6949 --- /dev/null +++ b/examples/52_memory_add_loop.txt @@ -0,0 +1,42 @@ +--- test\listing_0052_memory_add_loop execution --- +mov dx, 6 ; dx:0x0->0x6 ip:0x0->0x3 +mov bp, 1000 ; bp:0x0->0x3e8 ip:0x3->0x6 +mov si, 0 ; ip:0x6->0x9 +mov word [bp+si], si ; ip:0x9->0xb +add si, 2 ; si:0x0->0x2 ip:0xb->0xe +cmp si, dx ; ip:0xe->0x10 flags:->CPAS +jne $-7 ; ip:0x10->0x9 +mov word [bp+si], si ; ip:0x9->0xb +add si, 2 ; si:0x2->0x4 ip:0xb->0xe flags:CPAS-> +cmp si, dx ; ip:0xe->0x10 flags:->CAS +jne $-7 ; ip:0x10->0x9 +mov word [bp+si], si ; ip:0x9->0xb +add si, 2 ; si:0x4->0x6 ip:0xb->0xe flags:CAS->P +cmp si, dx ; ip:0xe->0x10 flags:P->PZ +jne $-7 ; ip:0x10->0x12 +mov bx, 0 ; ip:0x12->0x15 +mov si, 0 ; si:0x6->0x0 ip:0x15->0x18 +mov cx, [bp+si] ; ip:0x18->0x1a +add bx, cx ; ip:0x1a->0x1c +add si, 2 ; si:0x0->0x2 ip:0x1c->0x1f flags:PZ-> +cmp si, dx ; ip:0x1f->0x21 flags:->CPAS +jne $-9 ; ip:0x21->0x18 +mov cx, [bp+si] ; cx:0x0->0x2 ip:0x18->0x1a +add bx, cx ; bx:0x0->0x2 ip:0x1a->0x1c flags:CPAS-> +add si, 2 ; si:0x2->0x4 ip:0x1c->0x1f +cmp si, dx ; ip:0x1f->0x21 flags:->CAS +jne $-9 ; ip:0x21->0x18 +mov cx, [bp+si] ; cx:0x2->0x4 ip:0x18->0x1a +add bx, cx ; bx:0x2->0x6 ip:0x1a->0x1c flags:CAS->P +add si, 2 ; si:0x4->0x6 ip:0x1c->0x1f +cmp si, dx ; ip:0x1f->0x21 flags:P->PZ +jne $-9 ; ip:0x21->0x23 + +Final registers: + bx: 0x0006 (6) + cx: 0x0004 (4) + dx: 0x0006 (6) + bp: 0x03e8 (1000) + si: 0x0006 (6) + ip: 0x0023 (35) + flags: PZ diff --git a/src/main.c b/src/main.c index 21e7ac2..124a767 100644 --- a/src/main.c +++ b/src/main.c @@ -130,13 +130,14 @@ int simulate(FILE *src) { fprintf(stderr, "ERROR: Failed to decode instruction at 0x%08x: %s\n", state.ip, decode_error_to_str(err)); return -1; } - execute_instruction(&state, &inst); + execute_instruction(&mem, &state, &inst); } 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(" dx: 0x%04x (%d)\n", state.dx, state.dx); 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); diff --git a/src/sim8086.c b/src/sim8086.c index 53a9cdc..87553e3 100644 --- a/src/sim8086.c +++ b/src/sim8086.c @@ -42,8 +42,7 @@ static void reg_or_mem_to_str(char *buff, size_t max_size, struct reg_or_mem_val } static void src_to_str(char *buff, size_t max_size, struct src_value *value) { - switch (value->variant) - { + switch (value->variant) { case SRC_VALUE_REG: strncpy(buff, reg_to_str(value->reg), max_size); break; @@ -71,8 +70,7 @@ static const char *operation_to_str(enum operation op) { } static void instruction_to_str(char *buff, size_t max_size, struct instruction *inst) { - switch (inst->op) - { + switch (inst->op) { case OP_MOV: case OP_CMP: case OP_SUB: diff --git a/src/sim8086.h b/src/sim8086.h index e502c59..406c2a8 100644 --- a/src/sim8086.h +++ b/src/sim8086.h @@ -95,6 +95,7 @@ struct src_value { }; }; +// TODO: Store "wide" flag on instruction, it is useful to know when doing most operations struct instruction { enum operation op; struct reg_or_mem_value dest; diff --git a/src/sim8086_decoder.c b/src/sim8086_decoder.c index 283d312..43b5069 100644 --- a/src/sim8086_decoder.c +++ b/src/sim8086_decoder.c @@ -43,8 +43,7 @@ static i16 extend_sign_bit(i8 number) { } const char *decode_error_to_str(enum decode_error err) { - switch (err) - { + switch (err) { case DECODE_OK: return "ok"; case DECODE_ERR_EOF: @@ -83,19 +82,19 @@ static void decode_reg_or_mem( value->is_reg = true; value->reg = decode_reg(rm, wide); } else if (mod == 0b10) { // Mod = 0b10, memory with i16 displacement - i16 displacement = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + i16 displacement = pull_u16_at(mem, addr); value->is_reg = false; value->mem.base = decode_mem_base(rm); value->mem.disp = displacement; } else if (mod == 0b01) { // Mod = 0b01, memory with i8 displacement - i8 displacement = pull_byte_at(mem, addr); + i8 displacement = pull_u8_at(mem, addr); value->is_reg = false; value->mem.base = decode_mem_base(rm); value->mem.disp = extend_sign_bit(displacement); } else if (mod == 0b00) { // Mod = 0b00, memory no displacement (most of the time) value->is_reg = false; if (rm == 0b110) { // Direct address - u16 address = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + u16 address = pull_u16_at(mem, addr); value->mem.base = MEM_BASE_DIRECT_ADDRESS; value->mem.disp = address; } else { @@ -130,11 +129,11 @@ static void deocde_reg_or_mem_to_src( // TODO: add handling for 'DECODE_ERR_MISSING_BYTES' // Handy reference: Table 4-12. 8086 Instruction Encoding enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instruction *output) { - u8 byte1 = pull_byte_at(mem, addr); + u8 byte1 = pull_u8_at(mem, addr); // MOVE: Register memory to/from register if ((byte1 & 0b11111100) == 0b10001000) { - u8 byte2 = pull_byte_at(mem, addr); + u8 byte2 = pull_u8_at(mem, addr); bool wide = byte1 & 0b1; bool direction = (byte1 & 0b10) >> 1; @@ -164,16 +163,16 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr if (wide) { output->src.variant = SRC_VALUE_IMMEDIATE16; - output->src.immediate = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + output->src.immediate = pull_u16_at(mem, addr); } else { output->src.variant = SRC_VALUE_IMMEDIATE8; - output->src.immediate = pull_byte_at(mem, addr); + output->src.immediate = pull_u8_at(mem, addr); } // MOVE: Immediate to register/memory } else if ((byte1 & 0b11111110) == 0b11000110) { - u8 byte2 = pull_byte_at(mem, addr); + u8 byte2 = pull_u8_at(mem, addr); bool wide = byte1 & 0b1; u8 mod = (byte2 & 0b11000000) >> 6; @@ -184,10 +183,10 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr if (wide) { output->src.variant = SRC_VALUE_IMMEDIATE16; - output->src.immediate = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + output->src.immediate = pull_u16_at(mem, addr); } else { output->src.variant = SRC_VALUE_IMMEDIATE8; - output->src.immediate = pull_byte_at(mem, addr); + output->src.immediate = pull_u8_at(mem, addr); } // MOVE: Memory to accumulator @@ -200,9 +199,9 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr bool wide = byte1 & 0b1; if (wide) { - output->src.mem.disp = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + output->src.mem.disp = pull_u16_at(mem, addr); } else { - output->src.mem.disp = pull_byte_at(mem, addr); + output->src.mem.disp = pull_u8_at(mem, addr); } // MOVE: Accumulator to memory @@ -216,9 +215,9 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr output->dest.mem.base = MEM_BASE_DIRECT_ADDRESS; if (wide) { - output->dest.mem.disp = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + output->dest.mem.disp = pull_u16_at(mem, addr); } else { - output->dest.mem.disp = pull_byte_at(mem, addr); + output->dest.mem.disp = pull_u8_at(mem, addr); } // ADD/SUB/CMP: Reg/memory with register to either @@ -235,7 +234,7 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr bool wide = byte1 & 0b01; bool direction = (byte1 & 0b10) >> 1; - u8 byte2 = pull_byte_at(mem, addr); + u8 byte2 = pull_u8_at(mem, addr); u8 mod = (byte2 & 0b11000000) >> 6; u8 reg = (byte2 & 0b00111000) >> 3; u8 rm = byte2 & 0b00000111; @@ -252,7 +251,7 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr // ADD/SUB/CMP: immediate with register/memory } else if ((byte1 & 0b11111100) == 0b10000000) { - u8 byte2 = pull_byte_at(mem, addr); + u8 byte2 = pull_u8_at(mem, addr); u8 variant = (byte2 & 0b00111000) >> 3; if (variant == 0b000) { @@ -273,14 +272,14 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr if (wide) { output->src.variant = SRC_VALUE_IMMEDIATE16; if (sign_extend) { - output->src.immediate = pull_byte_at(mem, addr); + output->src.immediate = pull_u8_at(mem, addr); output->src.immediate = extend_sign_bit(output->src.immediate); } else { - output->src.immediate = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + output->src.immediate = pull_u16_at(mem, addr); } } else { output->src.variant = SRC_VALUE_IMMEDIATE8; - output->src.immediate = pull_byte_at(mem, addr); + output->src.immediate = pull_u8_at(mem, addr); } // ADD/SUB/CMP: immediate with accumulator @@ -301,22 +300,22 @@ enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instr if (wide) { output->src.variant = SRC_VALUE_IMMEDIATE16; - output->src.immediate = pull_byte_at(mem, addr) | (pull_byte_at(mem, addr) << 8); + output->src.immediate = pull_u16_at(mem, addr); } else { output->src.variant = SRC_VALUE_IMMEDIATE8; - output->src.immediate = pull_byte_at(mem, addr); + output->src.immediate = pull_u8_at(mem, addr); } // Conditional jumps } else if ((byte1 & 0b11110000) == 0b01110000) { - i8 jmp_offset = pull_byte_at(mem, addr); + i8 jmp_offset = pull_u8_at(mem, addr); u8 opcode = byte1 & 0b00001111; output->op = cond_jmp_lookup[opcode]; output->jmp_offset = jmp_offset; // Conditional loop jumps } else if ((byte1 & 0b11111100) == 0b11100000) { - i8 jmp_offset = pull_byte_at(mem, addr); + i8 jmp_offset = pull_u8_at(mem, addr); u8 opcode = byte1 & 0b00000011; output->op = cond_loop_jmp_lookup[opcode]; output->jmp_offset = jmp_offset; diff --git a/src/sim8086_memory.c b/src/sim8086_memory.c index 514eb19..b2d45c7 100644 --- a/src/sim8086_memory.c +++ b/src/sim8086_memory.c @@ -25,12 +25,31 @@ int load_mem_from_file(struct memory *mem, const char *filename, u32 start) { } // TODO: Make this error some kind of error, when reading past end -u8 read_byte_at(struct memory *mem, u16 address) { +u8 read_u8_at(struct memory *mem, u16 address) { return mem->mem[address % MEMORY_SIZE]; } -u8 pull_byte_at(struct memory *mem, u16 *address) { - u8 byte = read_byte_at(mem, *address); +u16 read_u16_at(struct memory *mem, u16 address) { + return read_u8_at(mem, address) | (read_u8_at(mem, address+1) << 8); +} + +void write_u8_at(struct memory *mem, u16 address, u8 value) { + mem->mem[address % MEMORY_SIZE] = value; +} + +void write_u16_at(struct memory *mem, u16 address, u16 value) { + write_u8_at(mem, address+0, (value >> 0) & 0xFF); + write_u8_at(mem, address+1, (value >> 8) & 0xFF); +} + +u16 pull_u16_at(struct memory *mem, u16 *address) { + u16 value = read_u16_at(mem, *address); + (*address) += 2; + return value; +} + +u8 pull_u8_at(struct memory *mem, u16 *address) { + u8 byte = read_u8_at(mem, *address); (*address)++; return byte; } \ No newline at end of file diff --git a/src/sim8086_simulator.c b/src/sim8086_simulator.c index db929b4..3ef9eda 100644 --- a/src/sim8086_simulator.c +++ b/src/sim8086_simulator.c @@ -1,118 +1,153 @@ -u16 read_reg_value(struct cpu_state *state, enum reg_value reg) +u16 read_reg_value(struct cpu_state *cpu, 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; + switch (reg) { + case REG_AL: return cpu->ax & 0xFF; + case REG_CL: return cpu->cx & 0xFF; + case REG_DL: return cpu->dx & 0xFF; + case REG_BL: return cpu->bx & 0xFF; + case REG_AH: return (cpu->ax >> 8) & 0xFF; + case REG_CH: return (cpu->cx >> 8) & 0xFF; + case REG_DH: return (cpu->dx >> 8) & 0xFF; + case REG_BH: return (cpu->bx >> 8) & 0xFF; + case REG_AX: return cpu->ax; + case REG_CX: return cpu->cx; + case REG_DX: return cpu->dx; + case REG_BX: return cpu->bx; + case REG_SP: return cpu->sp; + case REG_BP: return cpu->bp; + case REG_SI: return cpu->si; + case REG_DI: return cpu->di; default: panic("Unhandled register '%s'", reg_to_str(reg)); } } -void write_reg_value(struct cpu_state *state, enum reg_value reg, u16 value) +void write_reg_value(struct cpu_state *cpu, enum reg_value reg, u16 value) { - switch (reg) - { + switch (reg) { case REG_AL: - state->ax = (state->ax & 0xFF00) & value; + cpu->ax = (cpu->ax & 0xFF00) & value; break; case REG_CL: - state->cx = (state->cx & 0xFF00) & value; + cpu->cx = (cpu->cx & 0xFF00) & value; break; case REG_DL: - state->dx = (state->dx & 0xFF00) & value; + cpu->dx = (cpu->dx & 0xFF00) & value; break; case REG_BL: - state->bx = (state->bx & 0xFF00) & value; + cpu->bx = (cpu->bx & 0xFF00) & value; break; case REG_AH: - state->ax = (state->ax & 0x00FF) & (value << 8); + cpu->ax = (cpu->ax & 0x00FF) & (value << 8); break; case REG_CH: - state->cx = (state->cx & 0x00FF) & (value << 8); + cpu->cx = (cpu->cx & 0x00FF) & (value << 8); break; case REG_DH: - state->dx = (state->dx & 0x00FF) & (value << 8); + cpu->dx = (cpu->dx & 0x00FF) & (value << 8); break; case REG_BH: - state->bx = (state->bx & 0x00FF) & (value << 8); + cpu->bx = (cpu->bx & 0x00FF) & (value << 8); break; case REG_AX: - state->ax = value; + cpu->ax = value; break; case REG_CX: - state->cx = value; + cpu->cx = value; break; case REG_DX: - state->dx = value; + cpu->dx = value; break; case REG_BX: - state->bx = value; + cpu->bx = value; break; case REG_SP: - state->sp = value; + cpu->sp = value; break; case REG_BP: - state->bp = value; + cpu->bp = value; break; case REG_SI: - state->si = value; + cpu->si = value; break; case REG_DI: - state->di = value; + cpu->di = value; break; default: panic("Unhandled register '%s'", reg_to_str(reg)); } } -u16 read_src_value(struct cpu_state *state, struct src_value *src) { - switch (src->variant) - { +u16 read_mem_base_value(struct cpu_state *cpu, enum mem_base base) { + switch (base) { + case MEM_BASE_BX_SI: return read_reg_value(cpu, REG_BX) + read_reg_value(cpu, REG_SI); + case MEM_BASE_BX_DI: return read_reg_value(cpu, REG_BX) + read_reg_value(cpu, REG_DI); + case MEM_BASE_BP_SI: return read_reg_value(cpu, REG_BP) + read_reg_value(cpu, REG_SI); + case MEM_BASE_BP_DI: return read_reg_value(cpu, REG_BP) + read_reg_value(cpu, REG_DI); + case MEM_BASE_SI: return read_reg_value(cpu, REG_SI); + case MEM_BASE_DI: return read_reg_value(cpu, REG_DI); + case MEM_BASE_BP: return read_reg_value(cpu, REG_BP); + case MEM_BASE_BX: return read_reg_value(cpu, REG_BX); + default: return 0; + } +} + +u16 calculate_mem_address(struct cpu_state *cpu, struct mem_value *addr) { + if (addr->base == MEM_BASE_DIRECT_ADDRESS) { + return addr->direct_address; + } else { + return read_mem_base_value(cpu, addr->base) + addr->disp; + } +} + +u16 read_mem_value(struct memory *mem, struct cpu_state *cpu, struct mem_value *value, bool wide) { + u16 addr = calculate_mem_address(cpu, value); + + return wide ? read_u16_at(mem, addr) : read_u8_at(mem, addr); +} + +void write_mem_value(struct memory *mem, struct cpu_state *cpu, struct mem_value *location, u16 value, bool wide) { + u16 addr = calculate_mem_address(cpu, location); + + if (wide) { + write_u16_at(mem, addr, value); + } else { + write_u8_at(mem, addr, value); + } +} + +u16 read_src_value(struct memory *mem, struct cpu_state *cpu, struct src_value *src, bool wide) { + switch (src->variant) { case SRC_VALUE_REG: - return read_reg_value(state, src->reg); + return read_reg_value(cpu, src->reg); case SRC_VALUE_IMMEDIATE8: case SRC_VALUE_IMMEDIATE16: return src->immediate; case SRC_VALUE_MEM: - todo("Handle read from memory"); + return read_mem_value(mem, cpu, &src->mem, wide); 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) { +u16 read_reg_or_mem_value(struct memory *mem, struct cpu_state *cpu, struct reg_or_mem_value *reg_or_mem, bool wide) { if (reg_or_mem->is_reg) { - return read_reg_value(state, reg_or_mem->reg); + return read_reg_value(cpu, reg_or_mem->reg); } else { - todo("Handle read from memory"); + return read_mem_value(mem, cpu, ®_or_mem->mem, wide); } } -void write_src_or_mem_value(struct cpu_state *state, struct reg_or_mem_value *reg_or_mem, u16 value) { + +void write_reg_or_mem_value(struct memory *mem, struct cpu_state *cpu, struct reg_or_mem_value *reg_or_mem, u16 value, bool wide) { if (reg_or_mem->is_reg) { - write_reg_value(state, reg_or_mem->reg, value); + write_reg_value(cpu, reg_or_mem->reg, value); } else { - todo("Handle write to memory"); + write_mem_value(mem, cpu, ®_or_mem->mem, value, wide); } } bool is_reg_16bit(enum reg_value reg) { - switch (reg) - { + switch (reg) { case REG_AL: case REG_CL: case REG_DL: @@ -140,66 +175,68 @@ bool are_instruction_operands_16bit(struct instruction *inst) { return is_reg_16bit(inst->dest.reg); } else if (inst->src.variant == SRC_VALUE_REG) { return is_reg_16bit(inst->src.reg); + } else if (inst->src.variant == SRC_VALUE_IMMEDIATE8) { + return false; + } else if (inst->src.variant == SRC_VALUE_IMMEDIATE16) { + return true; } else { - return inst->src.variant == SRC_VALUE_IMMEDIATE16; + panic("Failed to determine instruction width\n"); } } -void execute_instruction(struct cpu_state *state, struct instruction *inst) { - switch (inst->op) - { +void update_sign_flag(struct cpu_state *cpu, struct instruction *inst, u16 result) { + if (are_instruction_operands_16bit(inst)) { + cpu->flags.sign = (result >> 15) & 0b1; + } else { + cpu->flags.sign = (result >> 7) & 0b1; + } +} + +void execute_instruction(struct memory *mem, struct cpu_state *cpu, struct instruction *inst) { + switch (inst->op) { case OP_MOV: { - u16 src_value = read_src_value(state, &inst->src); - write_src_or_mem_value(state, &inst->dest, src_value); + bool wide = are_instruction_operands_16bit(inst); + u16 src_value = read_src_value(mem, cpu, &inst->src, wide); + write_reg_or_mem_value(mem, cpu, &inst->dest, src_value, wide); break; } case OP_ADD: { - u16 dest_value = read_src_or_mem_value(state, &inst->dest); - u16 src_value = read_src_value(state, &inst->src); + bool wide = are_instruction_operands_16bit(inst); + u16 dest_value = read_reg_or_mem_value(mem, cpu, &inst->dest, wide); + u16 src_value = read_src_value(mem, cpu, &inst->src, wide); 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; - } + cpu->flags.zero = result == 0; + update_sign_flag(cpu, inst, result); - write_src_or_mem_value(state, &inst->dest, result); + write_reg_or_mem_value(mem, cpu, &inst->dest, result, wide); break; } case OP_SUB: { - u16 dest_value = read_src_or_mem_value(state, &inst->dest); - u16 src_value = read_src_value(state, &inst->src); + bool wide = are_instruction_operands_16bit(inst); + u16 dest_value = read_reg_or_mem_value(mem, cpu, &inst->dest, wide); + u16 src_value = read_src_value(mem, cpu, &inst->src, wide); 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; - } + cpu->flags.zero = result == 0; + update_sign_flag(cpu, inst, result); - write_src_or_mem_value(state, &inst->dest, result); + write_reg_or_mem_value(mem, cpu, &inst->dest, result, wide); break; } case OP_CMP: { - u16 dest_value = read_src_or_mem_value(state, &inst->dest); - u16 src_value = read_src_value(state, &inst->src); + bool wide = are_instruction_operands_16bit(inst); + u16 dest_value = read_reg_or_mem_value(mem, cpu, &inst->dest, wide); + u16 src_value = read_src_value(mem, cpu, &inst->src, wide); 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; - } + cpu->flags.zero = result == 0; + update_sign_flag(cpu, inst, result); break; } case OP_JNE: { - if (!state->flags.zero) { - i8 jmp_offset = inst->jmp_offset; - state->ip += jmp_offset; + if (!cpu->flags.zero) { + cpu->ip += inst->jmp_offset; } break;