From b511c6a620a5391e9a104d9f20c6c929c7693a40 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Thu, 20 Mar 2025 08:19:20 +0700 Subject: [PATCH] Clean up/inline functions and clear out TODOs --- decoding.odin | 34 +++++++++++++++++++------ printing.odin | 69 ++++++++------------------------------------------- sim8086.odin | 42 ------------------------------- types.odin | 1 + 4 files changed, 38 insertions(+), 108 deletions(-) diff --git a/decoding.odin b/decoding.odin index da9f596..06e78c7 100644 --- a/decoding.odin +++ b/decoding.odin @@ -4,6 +4,10 @@ import "core:fmt" import "core:math" import "core:strings" +get_i16 :: proc(data: []u8) -> i16 { + return (i16)(data[1]) << 8 | (i16)(data[0]) +} + get_op :: proc(inst: Instruction) -> (Op, bool) { op: Op interseg: bool @@ -12,8 +16,6 @@ get_op :: proc(inst: Instruction) -> (Op, bool) { case 0b000: op = .INC case 0b001: op = .DEC case 0b010: op = .CALL - // TODO: We really have to fix this because we shouldn't be figuring out if this - // is an intersegment here case 0b011: op = .CALL; interseg = true case 0b100: op = .JMP case 0b101: op = .JMP; interseg = true @@ -137,10 +139,20 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr v_flag := data[0] & 0b10 != 0 operand = v_flag ? RegisterId { id = 1, access = .Low } : Immediate { value = 1 } case .Repeat: - operand = get_repeat_op(data[1]) + bits := (data[1] & 0b1110) >> 1 + w := (data[1] & 0b1) == 1 ? "w" : "b" + rep: string + switch bits { + case 0b010: rep = "movs" + case 0b011: rep = "cmps" + case 0b101: rep = "stos" + case 0b110: rep = "lods" + case 0b111: rep = "scas" + } + operand = Repeat(fmt.aprintf("%s%s", rep, w)) processed^ += 1 case .DirectWithinSegment: - value := (int)(get_i16(data[1:])) + total_bytes_processed + 3 + value := (int)(get_i16(data[1:])) + CPU.total_bytes_processed + 3 operand = Immediate { value = u16(value), size = .Signed16 } processed^ += 2 case .Intersegment: @@ -162,8 +174,16 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read: processed := 1 curr_byte := data[idx] - inst, ok := try_find_instruction(curr_byte) - if !ok { + found_inst: bool + inst: InstructionInfo + for i in instructions { + if i.encoding == (curr_byte & i.mask) { + found_inst = true + inst = i + break + } + } + if !found_inst { instruction = { opname = .UNKNOWN, bytes_read = 1, @@ -240,6 +260,6 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read: has_lock = false has_segment = nil - total_bytes_processed = idx + CPU.total_bytes_processed = idx } } diff --git a/printing.odin b/printing.odin index 1273896..9da9bb8 100644 --- a/printing.odin +++ b/printing.odin @@ -3,9 +3,17 @@ package sim_8086 import "core:fmt" import "core:math" import "core:strings" +import "core:reflect" instruction_builder := strings.builder_make() +RIGHT_ALIGN_AMOUNT := 35 + +operand_is :: proc($T: typeid, opr: Operand) -> bool { + _, ok := opr.(T) + return ok +} + calculate_effective_address :: proc(r_m: u8) -> string { val: string switch r_m { @@ -66,63 +74,6 @@ get_displacement_string :: proc(displacement: Displacement) -> string { return disp } -get_opname :: proc(inst: Instruction) -> (string, bool) { - name: string - interseg: bool - if inst.opname == .TBD2 { - switch inst.raw_data[1] & 0b00111000 >> 3 { - case 0b000: name = "inc" - case 0b001: name = "dec" - case 0b010: name = "call" - // TODO: We really have to fix this because we shouldn't be figuring out if this - // is an intersegment here - case 0b011: name = "call"; interseg = true - case 0b100: name = "jmp" - case 0b101: name = "jmp"; interseg = true - case 0b110: name = "push" - } - } else if inst.opname == .TBD5 { - switch inst.raw_data[1] & 0b00111000 >> 3 { - case 0b000: name = "test" - case 0b001: name = "dec" - case 0b010: name = "not" - case 0b011: name = "neg" - case 0b100: name = "mul" - case 0b101: name = "imul" - case 0b110: name = "div" - case 0b111: name = "idiv" - } - } else if inst.opname == .TBD6 { - switch inst.raw_data[1] & 0b00111000 >> 3 { - case 0b000: name = "rol" - case 0b001: name = "ror" - case 0b010: name = "rcl" - case 0b011: name = "rcr" - case 0b100: name = "shl" - case 0b101: name = "shr" - case 0b111: name = "sar" - } - } else { - bits: u8 - if inst.opname == .TBD1 || inst.opname == .TBD3 { - bits = inst.raw_data[0] & 0b00111000 >> 3 - } else { - bits = inst.raw_data[1] & 0b00111000 >> 3 - } - switch bits { - case 0b000: name = "add" - case 0b001: name = "or" - case 0b010: name = "adc" - case 0b011: name = "sbb" - case 0b100: name = "and" - case 0b101: name = "sub" - case 0b110: name = "xor" - case 0b111: name = "cmp" - } - } - return name, interseg -} - get_register_name :: proc(reg_id: RegisterId) -> string { low_names := [?]string{"al", "cl", "dl", "bl"} high_names := [?]string{"ah", "ch", "dh", "bh"} @@ -194,8 +145,8 @@ get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruct src_str := get_operand_string(inst.src, inst.has_segment) opname: string is_interseg: bool - // TODO: Do the RTTI thing here with reflection - opname = strings.to_lower(fmt.aprintf("%s", inst.opname)) + + opname = strings.to_lower(reflect.enum_string(inst.opname)) if dst_str == "" { interseg_string: string diff --git a/sim8086.odin b/sim8086.odin index 4f8134a..af61fc2 100644 --- a/sim8086.odin +++ b/sim8086.odin @@ -5,13 +5,6 @@ import "core:fmt" import "core:math" import "core:strings" -RIGHT_ALIGN_AMOUNT := 35 - -// TODO: We completely botched this; ah and al refer to the ax register, they are not -// the low parts to sp, bp, si, di registers apparently you can't access those like that. -// We have to change how we coded this out. Likely we have to remove bytename as an option -// and then have some kind of flag when you're doing a dst or src operand specifying -// if it's the high or low part, not sure how to go about that registers := [?]Register { {fullname = "ax", code = 0b000}, {fullname = "cx", code = 0b001}, @@ -35,41 +28,6 @@ CPU := Cpu { memory = make([dynamic]u8, 65536) } -// TODO: I don't like this here -total_bytes_processed := 0 - -get_i16 :: proc(data: []u8) -> i16 { - return (i16)(data[1]) << 8 | (i16)(data[0]) -} - -operand_is :: proc($T: typeid, opr: Operand) -> bool { - _, ok := opr.(T) - return ok -} - -get_repeat_op :: proc(data: u8) -> Repeat { - bits := (data & 0b1110) >> 1 - w := (data & 0b1) == 1 ? "w" : "b" - rep: string - switch bits { - case 0b010: rep = "movs" - case 0b011: rep = "cmps" - case 0b101: rep = "stos" - case 0b110: rep = "lods" - case 0b111: rep = "scas" - } - return Repeat(fmt.aprintf("%s%s", rep, w)) -} - -try_find_instruction :: proc(b: u8) -> (InstructionInfo, bool) { - for inst in instructions { - if inst.encoding == (b & inst.mask) { - return inst, true - } - } - return InstructionInfo{}, false -} - main :: proc() { f,err := os.open(os.args[1]) if err != os.ERROR_NONE { diff --git a/types.odin b/types.odin index e432764..d7ade7f 100644 --- a/types.odin +++ b/types.odin @@ -135,4 +135,5 @@ Instruction :: struct { Cpu :: struct { flags: Flags, memory: [dynamic]u8, + total_bytes_processed: int }