From f46715f4c120c8acd446e81bb941fc08c836eec8 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 8 Jul 2023 19:20:54 +0900 Subject: [PATCH] Rework 16bit read/write to handle endianess --- Makefile | 2 +- shell.nix | 1 + src/dasm.h | 5 +- src/instructions/arithmetics.c | 15 +++--- src/instructions/memory.c | 16 +++--- src/interpretor.c | 97 +++++++++++++++++++++++++--------- src/interpretor.h | 14 ++++- 7 files changed, 103 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index 76780d6..96295aa 100644 --- a/Makefile +++ b/Makefile @@ -25,5 +25,5 @@ fclean: clean re: fclean all -dbg: $(CFLAGS += -g) +dbg: CFLAGS += -g -O0 dbg: re diff --git a/shell.nix b/shell.nix index b29bfb9..1337b7b 100644 --- a/shell.nix +++ b/shell.nix @@ -4,5 +4,6 @@ pkgs.mkShell { gcc gnumake valgrind + gdb ]; } diff --git a/src/dasm.h b/src/dasm.h index 4584fab..90d5f3f 100644 --- a/src/dasm.h +++ b/src/dasm.h @@ -63,5 +63,8 @@ unsigned get_inst_size(instruction_t inst, u_int8_t *binary, unsigned bin_size); void print_instruction(unsigned addr, instruction_t inst, unsigned inst_size, u_int8_t *binary, bool space); bool has_reg(const instruction_t *inst); -void *get_operand(const instruction_t *inst, unsigned i, state_t *state); +operand_t get_operand(const instruction_t *inst, unsigned i, state_t *state); bool is_operand_wide(const instruction_t *inst, unsigned i); + +void write_op(operand_t op, unsigned new_value); +unsigned read_op(operand_t op); diff --git a/src/instructions/arithmetics.c b/src/instructions/arithmetics.c index afc8826..6f31007 100644 --- a/src/instructions/arithmetics.c +++ b/src/instructions/arithmetics.c @@ -4,18 +4,15 @@ void sub(const instruction_t *self, state_t *state) { - void *from = get_operand(self, 0, state); - void *to = get_operand(self, 1, state); - unsigned old = is_operand_wide(self, 0) ? *(uint16_t *)from : *(uint8_t *)from; - unsigned minus = is_operand_wide(self, 1) ? *(uint16_t *)to : *(uint8_t *)to; + operand_t from = get_operand(self, 0, state); + operand_t to = get_operand(self, 1, state); + unsigned old = read_op(from); + unsigned minus = read_op(to); unsigned value = old - minus; - if (is_operand_wide(self, 0)) - *(uint16_t *)from = value; - else - *(uint8_t *)from = value; + write_op(from, value); - state->of = value != (is_operand_wide(self, 0) ? *(uint16_t *)from : *(uint8_t *)from); + state->of = value != read_op(from); state->cf = old < minus; state->sf = value & (is_operand_wide(self, 0) ? 0x8000 : 0x80); state->zf = value == 0; diff --git a/src/instructions/memory.c b/src/instructions/memory.c index 200a1b7..9bab316 100644 --- a/src/instructions/memory.c +++ b/src/instructions/memory.c @@ -8,18 +8,16 @@ void mov(const instruction_t *self, state_t *state) { - void *from = get_operand(self, 0, state); - void *to = get_operand(self, 1, state); + operand_t from = get_operand(self, 0, state); + operand_t to = get_operand(self, 1, state); - if (is_operand_wide(self, 0)) - *(uint16_t *)from = *(uint16_t *)to; - else - *(uint8_t *)from = *(uint8_t *)to; + // from = to; + write_op(from, read_op(to)); } void push(const instruction_t *self, state_t *state) { - uint16_t what = *(uint16_t *)get_operand(self, 0, state); + unsigned what = read_op(get_operand(self, 0, state)); if (is_operand_wide(self, 0)) state->memory[state->sp--] = what >> 8; @@ -28,7 +26,7 @@ void push(const instruction_t *self, state_t *state) void call(const instruction_t *self, state_t *state) { - uint16_t pc = *(uint16_t *)get_operand(self, 0, state); + uint16_t pc = read_op(get_operand(self, 0, state)); state->memory[state->sp--] = state->pc >> 8; state->memory[state->sp--] = state->pc & 0xFF; @@ -37,7 +35,7 @@ void call(const instruction_t *self, state_t *state) void jmp(const instruction_t *self, state_t *state) { - uint16_t pc = *(uint16_t *)get_operand(self, 0, state); + uint16_t pc = read_op(get_operand(self, 0, state)); state->pc = pc - get_inst_size(*self, state->binary + state->pc, state->binary_size - state->pc); } diff --git a/src/interpretor.c b/src/interpretor.c index 28984f1..3c42ef5 100644 --- a/src/interpretor.c +++ b/src/interpretor.c @@ -6,7 +6,36 @@ #include "dasm.h" #include "interpretor.h" -void *get_reg_operand(state_t *state, bool is16bit, unsigned reg) +void write_op(operand_t op, unsigned new_value) +{ + switch (op.type) { + case BIT8: + *op.ptr = new_value; + break; + case BIT16_SMALL_ENDIAN: + *(uint16_t *)op.ptr = new_value; + break; + case BIT16: + op.ptr[0] = new_value & 0xFF; + op.ptr[1] = new_value >> 8; + break; + } +} + +unsigned read_op(operand_t op) +{ + switch (op.type) { + case BIT8: + return *op.ptr; + case BIT16_SMALL_ENDIAN: + return *(uint16_t *)op.ptr; + case BIT16: + return op.ptr[0] | (op.ptr[1] << 8); + } + return 0; +} + +operand_t get_reg_operand(state_t *state, bool is16bit, unsigned reg) { uint8_t *registers8[8] = { &state->al, @@ -29,12 +58,13 @@ void *get_reg_operand(state_t *state, bool is16bit, unsigned reg) &state->di, }; - if (is16bit) - return registers16[reg]; - return registers8[reg]; + return (operand_t){ + .ptr = is16bit ? (uint8_t *)registers16[reg]: registers8[reg], + .type = is16bit ? BIT16_SMALL_ENDIAN : BIT8, + }; } -void *get_rm_operand(state_t *state, unsigned *imm_idx, bool is16bit) +operand_t get_rm_operand(state_t *state, unsigned *imm_idx, bool is16bit) { unsigned mod = state->binary[state->pc + 1] >> 6; unsigned rm = state->binary[state->pc + 1] & 0b111; @@ -44,37 +74,50 @@ void *get_rm_operand(state_t *state, unsigned *imm_idx, bool is16bit) if (mod == 0 && rm == 0b110) { *imm_idx += 2; - return state->memory + state->binary[state->pc + state->parse_data.imm_idx]; + return (operand_t){ + .ptr = state->memory + state->binary[state->pc + state->parse_data.imm_idx], + .type = is16bit ? BIT16 : BIT8 + }; } - int disp = mod == 0b10 - ? *(uint16_t*)&state->binary[state->pc + state->parse_data.imm_idx] - : (int8_t)state->binary[state->pc + state->parse_data.imm_idx]; + unsigned disp = read_op((operand_t){ + .ptr = &state->binary[state->pc + state->parse_data.imm_idx], + .type = mod == 0b10 ? BIT16 : BIT8} + ); state->parse_data.imm_idx += mod == 0b10 ? 2 : 1; + operand_t ret = {.ptr = NULL, .type = is16bit ? BIT16 : BIT8}; switch (rm) { case 0x00: - return state->memory + state->bx + state->si + disp; + ret.ptr = state->memory + state->bx + state->si + disp; + break; case 0x01: - return state->memory + state->bx + state->di + disp; + ret.ptr = state->memory + state->bx + state->di + disp; + break; case 0x02: - return state->memory + state->bp + state->si + disp; + ret.ptr = state->memory + state->bp + state->si + disp; + break; case 0x03: - return state->memory + state->bp + state->di + disp; + ret.ptr = state->memory + state->bp + state->di + disp; + break; case 0x04: - return state->memory + state->si + disp; + ret.ptr = state->memory + state->si + disp; + break; case 0x05: - return state->memory + state->di + disp; + ret.ptr = state->memory + state->di + disp; + break; case 0x06: - return state->memory + state->bp + disp; + ret.ptr = state->memory + state->bp + disp; + break; case 0x07: - return state->memory + state->bx + disp; + ret.ptr = state->memory + state->bx + disp; + break; } - return NULL; + return ret; } -void *get_operand(const instruction_t *inst, unsigned i, state_t *state) +operand_t get_operand(const instruction_t *inst, unsigned i, state_t *state) { - void *ret = NULL; + operand_t ret; unsigned imm_idx = 0; switch (inst->mode[i]) { @@ -83,21 +126,24 @@ void *get_operand(const instruction_t *inst, unsigned i, state_t *state) FALLTHROUGHT; case IMM8: imm_idx++; - ret = (void *)&state->binary[state->pc + state->parse_data.imm_idx]; + ret.ptr = &state->binary[state->pc + state->parse_data.imm_idx]; + ret.type = inst->mode[i] == IMM16 ? BIT16 : BIT8; break; case REL16: imm_idx += 2; state->parse_data.operand_holder[i] = state->pc + get_inst_size(*inst, state->binary + state->pc, state->binary_size - state->pc) + (int16_t)state->binary[state->pc + state->parse_data.imm_idx]; - ret = &state->parse_data.operand_holder[i]; + ret.ptr = &state->parse_data.operand_holder[i]; + ret.type = BIT16; break; case REL8: imm_idx++; state->parse_data.operand_holder[i] = state->pc + get_inst_size(*inst, state->binary + state->pc, state->binary_size - state->pc) + (int8_t)state->binary[state->pc + state->parse_data.imm_idx]; - ret = &state->parse_data.operand_holder[i]; + ret.ptr = &state->parse_data.operand_holder[i]; + ret.type = BIT8; break; case REG8: ret = get_reg_operand(state, false, (state->binary[state->pc + 1] & 0b111000) >> 3); @@ -176,9 +222,8 @@ void print_rm_value(state_t *state, instruction_t *inst) if (mod == 0b11) continue; - void *ptr = get_rm_operand(state, &imm, inst->mode[i] == R_M16); - uint16_t val = inst->mode[i] == R_M16 ? *(uint16_t *)ptr : *(uint8_t *)ptr; - printf(" ;[%04lx]%04x", (uint8_t *)ptr - state->memory, val); + operand_t operand = get_rm_operand(state, &imm, inst->mode[i] == R_M16); + printf(" ;[%04lx]%04x", operand.ptr - state->memory, read_op(operand)); } printf("\n"); } diff --git a/src/interpretor.h b/src/interpretor.h index 5d6ef58..c0c7eb5 100644 --- a/src/interpretor.h +++ b/src/interpretor.h @@ -65,7 +65,7 @@ typedef struct state { unsigned imm_idx; // A bunch of unsigneds to store temporary operands and return them as pointers. // instructions can't write to it, they are effectivly read-only. - unsigned operand_holder[5]; + uint8_t operand_holder[5]; } parse_data; } state_t; @@ -73,3 +73,15 @@ typedef struct { uint16_t source; uint16_t type; } syscall_t; + +enum operand_type { + BIT8, + BIT16, + BIT16_SMALL_ENDIAN, +}; + +typedef struct { + uint8_t *ptr; + enum operand_type type; +} operand_t; +