diff --git a/decoder8086.odin b/decoder8086.odin index 0c64264..faa15b0 100644 --- a/decoder8086.odin +++ b/decoder8086.odin @@ -2,6 +2,7 @@ package decoder_8086 import "core:os" import "core:fmt" +import "core:math" Register :: struct { fullname: string, @@ -22,6 +23,14 @@ RegMemMode :: enum { Register = 0b11, }; +OpCode :: enum { + MOV, + ADD, + SUB, + CMP, + JMP, +} + registers := [8]Register { {fullname = "ax", bytename = "al", code = 0b000}, {fullname = "cx", bytename = "cl", code = 0b001}, @@ -50,6 +59,11 @@ instructions := [?]Instruction { { mask = 0b11111111, encoding = 0b10001100, name = "mov", desc = "Segment register to register/memory" }, } +ParsedInstruction :: struct { + code: OpCode, + displacement: DisplacementMode, +} + inst_map := make(map[u8]Instruction) RIGHT_ALIGN_AMOUNT := 30 @@ -80,10 +94,122 @@ calculate_effective_address :: proc(r_m: u8) -> string { return val } +ModMemory :: struct {} +Mod8BitDisp :: i8 +Mod16BitDisp :: i16 +ModRegister :: struct {} + +DisplacementMode :: union { + ModMemory, + Mod8BitDisp, + Mod16BitDisp, + ModRegister, +} + +ModField :: struct { + displacement: DisplacementMode +} + +None :: struct {} +Disp8 :: i8 +Disp16 :: i16 +Displacement :: union { + None, + Disp8, + Disp16 +} + +RegisterId :: u8 +Immediate8 :: i8 +Immediate16 :: i16 +MemoryAddr :: struct { + addr_id: u8, + displacement: Displacement +} + +get_memory_string :: proc(memoryAddr: MemoryAddr) -> string { + disp: string + switch value in memoryAddr.displacement { + case None: + disp = "" + case Disp8: + if value != 0 { + disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value)) + } + case Disp16: + if value != 0 { + disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value)) + } + } + text := fmt.aprintf("[%s%s]", calculate_effective_address(memoryAddr.addr_id), disp) + return text +} + +MemoryType :: union { + RegisterId, + MemoryAddr +} + +OperandType :: union { + RegisterId, + Immediate8, + Immediate16, + MemoryAddr +} + +get_i16 :: proc(data: []u8) -> i16 { + return (i16)(data[1]) << 8 | (i16)(data[0]) +} + +parse_displacement :: proc(data: []u8) -> (displacement: DisplacementMode, disp_amount: int) { + mod := (data[0] & 0b11000000) >> 6 + disp: DisplacementMode + amount: int + switch mod { + case 0: + disp = ModMemory{} + case 1: + disp = (i8)(data[1]) + amount = 1 + case 2: + disp = get_i16(data[1:]) + amount = 2 + case 3: + disp = ModRegister{} + } + return disp, amount +} + +get_displacement_string :: proc(displacement: DisplacementMode) -> string { + disp := "" + #partial switch value in displacement { + case i8: + if value != 0 { + disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value)) + } + case i16: + if value != 0 { + disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value)) + } + } + return disp +} + +try_find_instruction :: proc(b: u8) -> (Instruction, bool) { + mask: u8 = 0xFF + for j in 0..=4 { + encoding := b & mask + if inst, ok := inst_map[encoding]; ok { + return inst, true + } + mask <<= 1 + } + return Instruction{}, false +} + main :: proc() { - ax := registers[0] - ax.value.full = 52428 f,err := os.open(len(os.args) > 1 ? os.args[1] : "./asm_files/01-02-39.bin") + // f,err := os.open(len(os.args) > 1 ? os.args[1] : "./asm_files/01-02-40.bin") if err != os.ERROR_NONE { os.exit(1) } @@ -101,69 +227,150 @@ main :: proc() { } if false { - for i in 0..> 3 + rm := mod_reg_rm & 0b00000111 + mod, disp_amount := parse_displacement(data[idx + 1:]) + switch disp_val in mod { + case ModMemory: + lhs2 = (RegisterId)(reg) + rhs2 = MemoryAddr{ addr_id = rm , displacement = None{} } + processed += 1 + case Mod8BitDisp: + lhs2 = (RegisterId)(reg) + rhs2 = MemoryAddr{ addr_id = rm , displacement = disp_val } + processed += 1 + case Mod16BitDisp: + lhs2 = (RegisterId)(reg) + rhs2 = MemoryAddr{ addr_id = rm , displacement = disp_val } + processed += 2 + case ModRegister: + lhs2 = (RegisterId)(rm) + rhs2 = (RegisterId)(reg) + processed += 1 + } + dst_reg := registers[rm] + } + + if flip_dst { + lhs2, rhs2 = rhs2, lhs2 + } + switch val in lhs2 { + case RegisterId: + lhs = fmt.aprintf("%s", is_word ? registers[val].fullname : registers[val].bytename) + case Immediate8: + lhs = fmt.aprintf("%d", val) + case Immediate16: + lhs = fmt.aprintf("%d", val) + case MemoryAddr: + lhs = get_memory_string(val) + } + switch val in rhs2 { + case RegisterId: + rhs = is_word ? registers[val].fullname : registers[val].bytename + case Immediate8: + rhs = fmt.aprintf("%d", val) + case Immediate16: + rhs = fmt.aprintf("%d", val) + case MemoryAddr: + rhs = get_memory_string(val) + } + full_inst := fmt.aprintf("%s %s, %s", inst_name, lhs, rhs) + processed += 1 + fmt.printf("%s %*[1]s a %08b", full_inst, RIGHT_ALIGN_AMOUNT - len(full_inst), ";;", curr_byte) + for i in 0..=processed { + fmt.printf(" %08b", data[processed + 1 + i]) + } + fmt.println() + idx += processed + if true { + continue + } + if curr_byte & 0b11111000 == 0b10001000 || curr_byte & 0b11111110 == 0b11000110 { + is_imm_mode := curr_byte & 0b11111110 == 0b11000110 is_word := curr_byte & 1 == 1 flip_src := curr_byte & 2 != 0 - disp_amount := 0 next_byte := data[processed + 1] - mod := (next_byte & 0b11000000) >> 6 reg := (next_byte & 0b00111000) >> 3 rm := next_byte & 0b00000111 dst_reg := registers[rm] - disp: string - if mod == 1 { - disp_byte := (i16)(data[processed + 2]) - disp_amount = 1 - disp = disp_byte == 0 ? "" : fmt.aprintf(" + %d", disp_byte) - } else if mod == 2 { - disp_byte := (i16)(data[processed + 3]) << 8 | (i16)(data[processed + 2]) - disp_amount = 2 - disp = disp_byte == 0 ? "" : fmt.aprintf(" + %d", disp_byte) - } else { - disp = "" - } - src_name: string - if mod == 3 { - // Register-to-register - src_name = is_word ? registers[rm].fullname : registers[rm].bytename - } else { - src_name = fmt.aprintf("[%s%s]", calculate_effective_address(rm), disp) - } + displacement, disp_amount := parse_displacement(data[processed + 1:]) - dst_name := is_word ? registers[reg].fullname : registers[reg].bytename + src_name, dst_name: string + // switch disp_val in displacement { + // case DisplaceMemoryMode: + // src_name = is_word ? registers[rm].fullname : registers[rm].bytename + // if is_imm_mode { + // if is_word { + // dst_name = fmt.aprintf("word %d", get_i16(data[processed+2:])) + // } else { + // dst_name = fmt.aprintf("byte %d", (i8)(data[processed+2])) + // } + // } + // disp_amount += is_word ? 2 : 1 + // case Displace8Bits: + // case Displace16Bits: + // case DisplaceRegisterMode: + // } + // if disp_val, ok := displacement.(DisplaceRegisterMode); ok { + // src_name = is_word ? registers[rm].fullname : registers[rm].bytename + // } else { + // src_name = fmt.aprintf("[%s%s]", calculate_effective_address(rm), get_displacement_string(displacement)) + // } - if flip_src { src_name, dst_name = dst_name, src_name } - - processed += 1 + ((int)(mod) % 3) + if flip_src && !is_imm_mode { src_name, dst_name = dst_name, src_name } inst_string := fmt.aprintf("mov %s, %s", src_name, dst_name) - fmt.printfln("%s %*[1]s %08b %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";; 1", curr_byte, next_byte) - } else if curr_byte & 0b1111_0000 == 0b10110000 { + fmt.printf("%s %*[1]s a %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";;", curr_byte) + for i in 0..=disp_amount { + fmt.printf(" %08b", data[processed + 1 + i]) + } + fmt.println() + processed += 1 + disp_amount + } else if curr_byte & 0b11110000 == 0b10110000 { is_word := curr_byte & 0b0000_1000 != 0 reg := curr_byte & 0b00000111 dst_name: string @@ -178,10 +385,14 @@ main :: proc() { processed += 1 } inst_string := fmt.aprintf("mov %s, %d", dst_name, imm) - fmt.printfln("%s %*[1]s %08b %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";; 2", curr_byte, data[processed + 1]) + fmt.printfln("%s %*[1]s b %08b %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";; 2", curr_byte, data[processed + 1]) + } else if curr_byte & 0b11111110 == 0b11000110 { + is_word := curr_byte & 1 != 0 + fmt.printfln("mov [%s], asdf ;; %08b %8b %8b", "", curr_byte, data[processed + 1], data[processed + 2]) } else { - fmt.printfln("unknown instruction ;; %b", curr_byte) + txt := "unknown instruction" + fmt.printfln("%s %*[1]s %8b", txt, RIGHT_ALIGN_AMOUNT - len(txt), ";;", curr_byte) } processed += 1 }