diff --git a/decoder8086.odin b/decoder8086.odin index 2cedc3e..c2e0b56 100644 --- a/decoder8086.odin +++ b/decoder8086.odin @@ -159,36 +159,54 @@ InstructionInfo :: struct { reg_info: Maybe(RegInfo), has_data: bool, has_address: bool, - has_accumulator: bool, + uses_accumulator: bool, has_segreg: bool, has_flip: bool, has_sign_extension: bool, is_jump: bool, + is_unary: bool, } // TODO: Maybe we can get rid of it since I don't have to specify the shift_offset, // not like it changes a lot reg_first_last := RegInfo{ in_first_byte = true, shift_offset = 0 } reg_second_middle := RegInfo{ in_first_byte = false, shift_offset = 3 } +reg_first_middle := RegInfo{ in_first_byte = true, shift_offset = 3 } instructions := [?]InstructionInfo { - { opname = .MOV, desc = "Register/memory to/from register", mask = 0b11111100, encoding = 0b10001000, + { opname = .MOV, desc = "Register/memory to/from register", mask = 0b11111100, encoding = 0b10001000, reg_info = reg_second_middle, has_address = true, word_size = LastBit{}, has_flip = true }, - { opname = .MOV, desc = "Immediate to register/memory", mask = 0b11111110, encoding = 0b11000110, + { opname = .MOV, desc = "Immediate to register/memory", mask = 0b11111110, encoding = 0b11000110, has_data = true, has_address = true, word_size = LastBit{}, }, - { opname = .MOV, desc = "Immediate to register", mask = 0b11110000, encoding = 0b10110000, + { opname = .MOV, desc = "Immediate to register", mask = 0b11110000, encoding = 0b10110000, reg_info = reg_first_last, has_data = true, word_size = FourthBit{} }, - { opname = .MOV, desc = "Memory to accumulator", mask = 0b11111110, encoding = 0b10100000, - has_flip = true, word_size = LastBit{}, has_accumulator = true }, - { opname = .MOV, desc = "Accumulator to memory", mask = 0b11111110, encoding = 0b10100010, - has_flip = true, word_size = LastBit{}, has_accumulator = true }, - { opname = .MOV, desc = "Register/memory to segment register", mask = 0b11111111, encoding = 0b10001110, + { opname = .MOV, desc = "Memory to accumulator", mask = 0b11111110, encoding = 0b10100000, + has_flip = true, word_size = LastBit{}, uses_accumulator = true }, + { opname = .MOV, desc = "Accumulator to memory", mask = 0b11111110, encoding = 0b10100010, + has_flip = true, word_size = LastBit{}, uses_accumulator = true }, + { opname = .MOV, desc = "Register/memory to segment register", mask = 0b11111111, encoding = 0b10001110, has_segreg = true, has_address = true, word_size = None{} }, - { opname = .MOV, desc = "Segment register to register/memory", mask = 0b11111111, encoding = 0b10001100, + { opname = .MOV, desc = "Segment register to register/memory", mask = 0b11111111, encoding = 0b10001100, has_segreg = true, has_address = true, word_size = None{} }, - { opname = .TBD, desc = "Reg/memory with register to either", mask = 0b11000100, encoding = 0b00000000, + { opname = .PUSH, desc = "", mask = 0b11111111, encoding = 0b11111111, + has_address = true, word_size = None{}, is_unary = true }, + { opname = .PUSH, desc = "", mask = 0b11111000, encoding = 0b01010000, + reg_info = reg_first_last, word_size = Force{}, is_unary = true }, + { opname = .PUSH, desc = "", mask = 0b11100111, encoding = 0b00000110, + has_segreg = true, reg_info = reg_first_middle, word_size = Force{}, is_unary = true }, + { opname = .POP, desc = "", mask = 0b11111111, encoding = 0b10001111, + has_address = true, word_size = None{}, is_unary = true }, + { opname = .POP, desc = "", mask = 0b11111000, encoding = 0b01011000, + reg_info = reg_first_last, word_size = Force{}, is_unary = true }, + { opname = .POP, desc = "", mask = 0b11100111, encoding = 0b00000111, + has_segreg = true, reg_info = reg_first_middle, word_size = None{}, is_unary = true }, + { opname = .XCHG, desc = "", mask = 0b11111110, encoding = 0b10000110, + reg_info = reg_second_middle, has_address = true, word_size = LastBit{}, has_flip = true}, + { opname = .XCHG, desc = "", mask = 0b11111000, encoding = 0b10010000, + reg_info = reg_first_last, uses_accumulator = true, word_size = Force{}, }, + { opname = .TBD, desc = "Reg/memory with register to either", mask = 0b11000100, encoding = 0b00000000, opcode_id = .First, reg_info = reg_second_middle, has_address = true, word_size = LastBit{}, has_flip = true }, - { opname = .TBD, desc = "Immediate to register/memory", mask = 0b11111100, encoding = 0b10000000, + { opname = .TBD, desc = "Immediate to register/memory", mask = 0b11111100, encoding = 0b10000000, opcode_id = .Second, has_data = true, has_address = true, word_size = LastBit{}, has_sign_extension = true }, { opname = .TBD, desc = "Immediate to accumulator", mask = 0b11000100, encoding = 0b00000100, @@ -299,6 +317,8 @@ get_memory_type_string :: proc(mem_type: OperandType, is_word: bool) -> string { string_val = get_memory_string(val) case Accumulator: string_val = fmt.aprintf("[%d]", val) + case SegmentRegister: + string_val = segment_registers[val].fullname } return string_val } @@ -383,13 +403,17 @@ main :: proc() { // asdf :u16 = 0b00000011_11101000 // asdf2 :i16 = (i16)(asdf) // fmt.printfln("%d", asdf2) + print_at_end := false read_next := false src_dst := true idx := 0 added_label := false line_count := 0 + // last_opname: string + last_opname: [3]byte instruction_builder := strings.builder_make() - instruction_list := make([dynamic]string, 128) + instruction_list := make([dynamic]string, 512) + fmt.println("bits 16") for idx < bytes_read { processed := 1 curr_byte := data[idx] @@ -422,6 +446,7 @@ main :: proc() { switch val in instruction.word_size { case LastBit: is_word = curr_byte & 1 == 1 case FourthBit: is_word = curr_byte & 0b0000_1000 != 0 + case Force: is_word = true case None: } @@ -459,6 +484,10 @@ main :: proc() { } else if mod == 3 { lhs2 = (RegisterId)(registers[rm].code) } + } else if instruction.has_segreg { + lhs2 = (SegmentRegister)(segment_registers[reg].code) + } else if instruction.uses_accumulator { + lhs2 = (RegisterId)(registers[0].code) } else { lhs2 = (RegisterId)(registers[reg].code) } @@ -470,9 +499,13 @@ main :: proc() { processed += word_signed ? 2 : 1 rhs2 = (OperandType)(word_signed ? (Immediate16)(get_i16(data[data_idx:])) : (Immediate8)(data[data_idx])) has_immediate = true - } else if instruction.has_accumulator { - processed += is_word ? 2 : 1 - rhs2 = (OperandType)(is_word ? (Accumulator)(get_i16(data[data_idx:])) : (Accumulator)(data[data_idx])) + } else if instruction.uses_accumulator { + if _, ok := instruction.word_size.(LastBit); ok { + processed += is_word ? 2 : 1 + rhs2 = (OperandType)(is_word ? (Accumulator)(get_i16(data[data_idx:])) : (Accumulator)(data[data_idx])) + } else { + rhs2 = (RegisterId)(reg) + } } else { rhs2 = (RegisterId)(reg) } @@ -500,6 +533,11 @@ main :: proc() { value := (i8)(data[idx+1]) + 2 full_inst = fmt.aprintf("%s $%s%d ; %d", strings.to_lower(opname), value >= 0 ? "+" : "", value, value - 2) processed += 1 + } else if instruction.is_unary { + if instruction.has_address { + size_string = "word " + } + full_inst = fmt.aprintf("%s %s%s", opname, size_string, lhs) } else { opname = strings.to_lower(opname) if opname == "mov" { @@ -512,13 +550,28 @@ main :: proc() { for i in 0..