package sim_8086 import "core:fmt" import "core:math" import "core:strings" instruction_builder := strings.builder_make() calculate_effective_address :: proc(r_m: u8) -> string { val: string switch r_m { case 0b000: val = "bx + si" case 0b001: val = "bx + di" case 0b010: val = "bp + si" case 0b011: val = "bp + di" case 0b100: val = "si" case 0b101: val = "di" case 0b110: val = "bp" case 0b111: val = "bx" } return val } get_memory_string :: proc(memoryAddr: MemoryAddr, has_segment: Maybe(Register)) -> 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)) } } seg_string: string if segreg, ok := has_segment.?; ok { seg_string = fmt.aprintf("%s:", segreg.fullname) } text := fmt.aprintf("%s[%s%s]", seg_string, calculate_effective_address(memoryAddr.addr_id), disp) return text } get_displacement_string :: proc(displacement: Displacement) -> 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 } 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"} switch reg_id.access { case .Full: return registers[reg_id.id].fullname case .Low: return low_names[reg_id.id] case .High: return high_names[reg_id.id % 4] } return "" } get_operand_string :: proc(operand: Operand, has_segment: Maybe(Register)) -> string { string_val: string switch val in operand { case None: string_val = "" case RegisterId: string_val = get_register_name(val) case Immediate8, ImmediateU8, Immediate16, DirectWithinSegment: string_val = fmt.aprintf("%d", val) case MemoryAddr: string_val = get_memory_string(val, has_segment) case DirectAddress: seg_string: string if segreg, ok := has_segment.?; ok { seg_string = fmt.aprintf("%s:", segreg.fullname) } string_val = fmt.aprintf("%s[%d]", seg_string, val) case SegmentRegister: string_val = segment_registers[val].fullname case Jump: string_val = fmt.aprintf("$%s%d", val >= 0 ? "+" : "", val) case VariablePort: string_val = variable_port.fullname case ShiftRotate: string_val = val ? "cl" : "1" case Repeat: string_val = (string)(val) case Intersegment: string_val = fmt.aprintf("%d:%d", val.cs, val.ip) } return string_val } get_unknown_inst_string :: proc(inst: Instruction) -> string { print_at_end := false txt := "unknown instruction" line := fmt.aprintf("%s %*[1]s %8b", txt, RIGHT_ALIGN_AMOUNT - len(txt), ";;", inst.raw_data[0]) return line } get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruction) { inst := instruction src_is_imm := operand_is(Immediate8, inst.src) || operand_is(Immediate16, inst.src) dst_is_bracketed := operand_is(MemoryAddr, inst.dst) || operand_is(DirectAddress, inst.dst) src_is_bracketed := operand_is(MemoryAddr, inst.src) || operand_is(DirectAddress, inst.src) shiftrot := operand_is(ShiftRotate, inst.src) size_string := "" if ((src_is_imm && dst_is_bracketed) || (dst_is_bracketed && shiftrot)) || (src_is_bracketed && operand_is(None, inst.dst)) { size_string = inst.is_word ? "word " : "byte " } if inst.has_lock { fmt.sbprint(&instruction_builder, "lock ") } dst_str := get_operand_string(inst.dst, inst.has_segment) src_str := get_operand_string(inst.src, inst.has_segment) opname: string is_interseg: bool if inst_info.check_second_encoding { opname,is_interseg = get_opname(inst) } else { // TODO: Do the RTTI thing here with reflection opname = strings.to_lower(fmt.aprintf("%s", inst.opname)) } if dst_str == "" { interseg_string: string if is_interseg { interseg_string = " far" } fmt.sbprintf(&instruction_builder, "%s%s %s%s", opname, interseg_string, size_string, src_str) } else { // note: i don't know why this is the case, but only the move has the word/byte // keyword next to the immediate, but other instructions have it on the memory address if opname == "mov" { fmt.sbprintf(&instruction_builder, "%s %s, %s%s", opname, dst_str, size_string, src_str) } else { fmt.sbprintf(&instruction_builder, "%s %s%s, %s", opname, size_string, dst_str, src_str) } } // Prepare padding and comment to add debug info b_len := strings.builder_len(instruction_builder) fmt.sbprintf(&instruction_builder, "%*[0]s", RIGHT_ALIGN_AMOUNT - b_len, ";;") if inst.has_lock { fmt.sbprintf(&instruction_builder, " lock") } if _,ok := inst.has_segment.?; ok { fmt.sbprintf(&instruction_builder, " segment") } for i in 0.. 0 { fmt.println() } repeating_op_count = 0 } else { repeating_op_count += 1 } copy(last_opname[:], op2[0:3]) fmt.println(op2) } }