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 { 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(RegisterId)) -> string { disp: string value := memoryAddr.displacement_value 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:", get_register_name(segreg)) } text := fmt.aprintf("%s[%s%s]", seg_string, calculate_effective_address(memoryAddr.addr_id), disp) return text } 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 reflect.enum_string(reg_id.name) case .Low: return low_names[int(reg_id.name)] case .High: return high_names[int(reg_id.name) % 4] } return "" } get_operand_string :: proc(operand: Operand, has_segment: Maybe(RegisterId)) -> string { string_val: string switch val in operand { case None: string_val = "" case RegisterId: string_val = get_register_name(val) case Immediate: switch val.size { case .Signed8: string_val = fmt.aprintf("%d", i8(val.value)) case .Unsigned8: string_val = fmt.aprintf("%d", u8(val.value)) case .Signed16: string_val = fmt.aprintf("%d", i16(val.value)) } 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:", get_register_name(segreg)) } string_val = fmt.aprintf("%s[%d]", seg_string, val) case Jump: string_val = fmt.aprintf("$%s%d", val >= 0 ? "+" : "", val) 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(Immediate, 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 := inst_info.opname == .TBD6 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 opname = strings.to_lower(reflect.enum_string(inst.opname)) if dst_str == "" { interseg_string: string if instruction.indirect_intersegment { 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) } }