package sim_8086 import "core:os" import "core:fmt" import "core:math" import "core:strings" import "core:reflect" get_operand_value :: proc(operand: Operand) -> i16 { #partial switch opr in operand { case Immediate: // fmt.printfln("0x%4x %d", i16(opr.value), opr.value) return i16(opr.value) case RegisterId: reg_val := CPU.registers[opr.name] switch opr.access { case .Low, .High: return i16(opr.access == .Low ? reg_val.low : reg_val.high) case .Full: return i16(reg_val.full) } } return 0 } set_register_value :: proc(reg: RegisterId, value: i16) { switch reg.access { case .Low: CPU.registers[reg.name].low = u8(value) case .High: CPU.registers[reg.name].high = u8(value) case .Full: CPU.registers[reg.name].full = i16(value) } } get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue { reg,_ := reflect.enum_from_name(Register, name) return &cpu.registers[reg] } check_zero_flag :: proc(value: i16) { CPU.flags[.ZF] = value == 0 } check_sign_flag :: proc(value: i16) { CPU.flags[.SF] = (value >> 15) & 0x1 == 1 } check_carry_flag :: proc(dst: i16, src: i16, is_add: bool) { CPU.flags[.CF] = is_add ? u32(dst) + u32(src) > 0xFFFF : src > dst } check_parity_flag :: proc(value: i16) { val := value bit_count := 0 val &= 0x00FF for val != 0 { if val & 0x1 == 1 { bit_count += 1 } val >>= 1 } CPU.flags[.PF] = val % 2 == 0 } check_auxiliary_carry_flag :: proc(dst: i16, src: i16, is_add: bool) { lhs, rhs := dst & 0xF, src & 0xF CPU.flags[.AF] = is_add ? lhs + rhs > 15 : lhs < rhs } check_flags :: proc(value: i16) { check_zero_flag(value) check_sign_flag(value) check_parity_flag(value) } execute_instruction :: proc(inst: Instruction) { if reg,ok := inst.dst.(RegisterId); ok { #partial switch inst.opname { case .MOV: src_val := get_operand_value(inst.src) set_register_value(reg, src_val) case .ADD: src_val := get_operand_value(inst.src) dst_val := get_operand_value(inst.dst) val := i16(CPU.registers[reg.name].full) + src_val set_register_value(reg, val) check_flags(val) check_auxiliary_carry_flag(dst_val, src_val, true) check_carry_flag(dst_val, src_val, true) case .SUB: src_val := get_operand_value(inst.src) dst_val := get_operand_value(inst.dst) val := i16(CPU.registers[reg.name].full) - src_val set_register_value(reg, val) check_flags(val) check_auxiliary_carry_flag(dst_val, src_val, false) check_carry_flag(dst_val, src_val, false) case .CMP: src_val := get_operand_value(inst.src) dst_val := get_operand_value(inst.dst) val := i16(CPU.registers[reg.name].full) - src_val check_flags(val) check_auxiliary_carry_flag(dst_val, src_val, false) check_carry_flag(dst_val, src_val, false) } } }