package sim_8086 import "core:fmt" import "core:math" import "core:strings" parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, processed: ^int, word: bool, has_segreg: Maybe(Register)) -> Operand { operand: Operand = None{} switch opinfo { case .None: case .Register: reg: u8 switch inst.reg_info { case .None: panic("Register is required but the encoded location is not provided") case .FirstByteLast3: reg = data[0] & 0b111 case .FirstByteMiddle3: reg = (data[0] >> 3) & 0b111 case .SecondByteMiddle3: reg = (data[1] >> 3) & 0b111 case .SecondByteLast3: reg = data[1] & 0b111 } operand = (RegisterId)(registers[reg].code) case .SegmentRegister: reg: u8 switch inst.reg_info { case .None: panic("Register is required but the encoded location is not provided") case .FirstByteLast3: reg = data[0] & 0b111 case .FirstByteMiddle3: reg = (data[0] >> 3) & 0b111 case .SecondByteMiddle3: reg = (data[1] >> 3) & 0b111 case .SecondByteLast3: reg = data[1] & 0b111 } operand = (SegmentRegister)(segment_registers[reg].code) case .RegisterMemory: mod := data[1] >> 6 rm := data[1] & 0b111 processed^ += 1 op: Operand if mod == 0 { if rm == 0b110 { op = (DirectAddress)(get_i16(data[2:])) processed^ += 2 } else { op = MemoryAddr{ addr_id = rm , displacement = None{} } } } else if mod == 1 { op = MemoryAddr{ addr_id = rm , displacement = (i8)(data[2]) } processed^ += 1 } else if mod == 2 { op = MemoryAddr{ addr_id = rm , displacement = get_i16(data[2:]) } processed^ += 2 } else if mod == 3 { op = (RegisterId)(registers[rm].code) } operand = op case .Immediate: data_idx := processed^ word_signed := word if inst.has_sign_extension { word_signed &&= data[0] & 0b0000_0010 == 0 } operand = (Operand)(word_signed ? (Immediate16)(get_i16(data[data_idx:])) : (Immediate8)(data[data_idx])) processed^ += word_signed ? 2 : 1 case .ImmediateUnsigned: operand = (ImmediateU8)(data[processed^]) processed^ += 1 case .Accumulator: operand = (RegisterId)(registers[0].code) case .DirectAddress: operand = (DirectAddress)(get_i16(data[1:])) processed^ += 2 case .Jump: processed^ += 1 // NOTE: In order to mimic the label offset, you have to take the value you got and add two operand = (Jump)((i8)(data[1]) + 2) case .VariablePort: operand = VariablePort{} case .ShiftRotate: v_flag := data[0] & 0b10 != 0 operand = (ShiftRotate)(v_flag) case .Repeat: operand = get_repeat_op(data[1]) processed^ += 1 case .DirectWithinSegment: value := (int)(get_i16(data[1:])) + total_bytes_processed + 3 operand = (DirectWithinSegment)(value) processed^ += 2 case .Intersegment: operand = Intersegment { ip = get_i16(data[1:]), cs = get_i16(data[3:]), } processed^ += 4 } return operand } decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read: int) { idx := 0 has_segment: Maybe(Register) has_lock: bool for idx < bytes_to_read { instruction: Instruction processed := 1 curr_byte := data[idx] inst, ok := try_find_instruction(curr_byte) if !ok { instruction = { opname = .UNKNOWN, bytes_read = 1, raw_data = data[idx:idx+1], } append(inst_list, instruction) idx += 1 continue } // Here we check if the instruction affects the next instruction if inst.opname == .LOCK { has_lock = true idx += 1 continue } else if inst.opname == .SEGMENT { reg := (curr_byte & 0b11000) >> 3 has_segment = segment_registers[reg] idx += 1 continue } else if inst.opname == .AAM { processed += 1 } debug_str: string // NOTE: This is a special case because it matches the bit pattern of .TBD5, // but the instruction itself is different if inst.opname == .TBD5 && (data[idx] & 0xFF) == 0b11110110 && (data[idx+1] & 0b00111000) == 0 { inst = test_inst } src_opr: Operand dst_opr: Operand word: bool flip: bool indirect_intersegment: bool op: Operand if inst.has_flip { flip = curr_byte & 2 != 0 } #partial switch inst.word_size { case .LastBit: word = curr_byte & 1 == 1 case .FourthBit: word = curr_byte & 0b0000_1000 != 0 case .Always16: word = true } dst_opr = parse_operand(inst, inst.dst, data[idx:], &processed, word, has_segment) src_opr = parse_operand(inst, inst.src, data[idx:], &processed, word, has_segment) if flip { src_opr, dst_opr = dst_opr, src_opr } processed += inst.consume_extra_bytes instruction.opname = inst.opname instruction.src = src_opr instruction.dst = dst_opr instruction.is_word = word instruction.bytes_read = processed instruction.raw_data = data[idx:idx+processed] instruction.debug_msg = debug_str instruction.info = inst instruction.has_lock = has_lock instruction.has_segment = has_segment // fmt.println(parsed_inst) append(inst_list, instruction) idx += processed has_lock = false has_segment = nil total_bytes_processed = idx } }