diff --git a/asm_files/list-0045.asm b/asm_files/list-0045.asm index 843f807..9e25fda 100644 --- a/asm_files/list-0045.asm +++ b/asm_files/list-0045.asm @@ -26,11 +26,11 @@ mov ds, bx mov es, cx mov al, 0x11 -mov bl, 0x33 +mov bh, 0x33 mov cl, 0x55 -mov dl, 0x77 +mov dh, 0x77 -mov al, bl +mov ah, bl mov cl, dh mov ss, ax diff --git a/decoding.odin b/decoding.odin index a28cea3..c319723 100644 --- a/decoding.odin +++ b/decoding.odin @@ -11,18 +11,17 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr 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 + 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 + } + if word { + operand = RegisterId { id = (int)(reg), access = .Full } + } else { + operand = RegisterId { id = (int)(reg % 4), access = reg < 4 ? .Low : .High } } - operand = (RegisterId)(registers[reg].code) case .SegmentRegister: reg: u8 switch inst.reg_info { @@ -57,7 +56,11 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr op = MemoryAddr{ addr_id = rm , displacement = get_i16(data[2:]) } processed^ += 2 } else if mod == 3 { - op = (RegisterId)(registers[rm].code) + if word { + op = RegisterId { id = (int)(rm), access = .Full } + } else { + op = RegisterId { id = (int)(rm % 4), access = rm < 4 ? .Low : .High } + } } operand = op case .Immediate: @@ -72,7 +75,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr operand = (ImmediateU8)(data[processed^]) processed^ += 1 case .Accumulator: - operand = (RegisterId)(registers[0].code) + operand = RegisterId { id = 0, access = word ? .Full : .Low } case .DirectAddress: operand = (DirectAddress)(get_i16(data[1:])) processed^ += 2 diff --git a/execution.odin b/execution.odin index b08c44a..574c4fd 100644 --- a/execution.odin +++ b/execution.odin @@ -9,16 +9,51 @@ execute_instruction :: proc(inst: Instruction) { #partial switch inst.opname { case .MOV: if reg_id,ok := inst.dst.(RegisterId); ok { + // val := registers[reg_id.id].value.full #partial switch val in inst.src { case Immediate8: - registers[reg_id].value.low = (u8)(val) + if reg_id.access == .Low { + registers[reg_id.id].value.low = (u8)(val) + } else { + registers[reg_id.id].value.high = (u8)(val) + } case ImmediateU8: - registers[reg_id].value.low = (u8)(val) + if reg_id.access == .Low { + registers[reg_id.id].value.low = (u8)(val) + } else { + registers[reg_id.id].value.high = (u8)(val) + } case Immediate16: - registers[reg_id].value.full = (u16)(val) + registers[reg_id.id].value.full = (u16)(val) case RegisterId: - registers[reg_id].value.full = registers[val].value.full + switch val.access { + case .Low, .High: + value := val.access == .Low ? registers[val.id].value.low : registers[val.id].value.high + if reg_id.access == .Low { + registers[reg_id.id].value.low = value + } else { + registers[reg_id.id].value.high = value + } + case .Full: + registers[reg_id.id].value.full = registers[val.id].value.full + } + case SegmentRegister: + registers[reg_id.id].value.full = segment_registers[val].value.full } + // fmt.printfln("%s:%04x->%04x", registers[reg_id].fullname, val, registers[reg_id].value.full) + } else if reg_id,ok := inst.dst.(SegmentRegister); ok { + // val := segment_registers[reg_id].value.full + #partial switch val in inst.src { + case Immediate8: + segment_registers[reg_id].value.low = (u8)(val) + case ImmediateU8: + segment_registers[reg_id].value.low = (u8)(val) + case Immediate16: + segment_registers[reg_id].value.full = (u16)(val) + case RegisterId: + segment_registers[reg_id].value.full = registers[val.id].value.full + } + // fmt.printfln("%s:%04x->%04x", segment_registers[reg_id].fullname, val, segment_registers[reg_id].value.full) } } } diff --git a/printing.odin b/printing.odin index 667cd2b..60f2f6f 100644 --- a/printing.odin +++ b/printing.odin @@ -123,13 +123,24 @@ get_opname :: proc(inst: Instruction) -> (string, bool) { return name, interseg } -get_operand_string :: proc(operand: Operand, is_word: bool, has_segment: Maybe(Register)) -> string { +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 = is_word ? registers[val].fullname : registers[val].bytename + string_val = get_register_name(val) case Immediate8, ImmediateU8, Immediate16, DirectWithinSegment: string_val = fmt.aprintf("%d", val) case MemoryAddr: @@ -147,7 +158,7 @@ get_operand_string :: proc(operand: Operand, is_word: bool, has_segment: Maybe(R case VariablePort: string_val = variable_port.fullname case ShiftRotate: - string_val = val ? registers[1].bytename : "1" + string_val = val ? "cl" : "1" case Repeat: string_val = (string)(val) case Intersegment: @@ -178,8 +189,8 @@ get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruct fmt.sbprint(&instruction_builder, "lock ") } - dst_str := get_operand_string(inst.dst, inst.is_word, inst.has_segment) - src_str := get_operand_string(inst.src, inst.is_word, inst.has_segment) + 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 { diff --git a/sim8086.odin b/sim8086.odin index bb6e0ec..e5f018d 100644 --- a/sim8086.odin +++ b/sim8086.odin @@ -7,15 +7,20 @@ import "core:strings" RIGHT_ALIGN_AMOUNT := 35 +// TODO: We completely botched this; ah and al refer to the ax register, they are not +// the low parts to sp, bp, si, di registers apparently you can't access those like that. +// We have to change how we coded this out. Likely we have to remove bytename as an option +// and then have some kind of flag when you're doing a dst or src operand specifying +// if it's the high or low part, not sure how to go about that registers := [8]Register { - {fullname = "ax", bytename = "al", code = 0b000}, - {fullname = "cx", bytename = "cl", code = 0b001}, - {fullname = "dx", bytename = "dl", code = 0b010}, - {fullname = "bx", bytename = "bl", code = 0b011}, - {fullname = "sp", bytename = "ah", code = 0b100}, - {fullname = "bp", bytename = "ch", code = 0b101}, - {fullname = "si", bytename = "dh", code = 0b110}, - {fullname = "di", bytename = "bh", code = 0b111}, + {fullname = "ax", code = 0b000}, + {fullname = "cx", code = 0b001}, + {fullname = "dx", code = 0b010}, + {fullname = "bx", code = 0b011}, + {fullname = "sp", code = 0b100}, + {fullname = "bp", code = 0b101}, + {fullname = "si", code = 0b110}, + {fullname = "di", code = 0b111}, } segment_registers := [4]Register { @@ -69,6 +74,8 @@ main :: proc() { } defer os.close(f) + what_to_print := len(os.args) >= 3 ? os.args[2] : "" + data := make([]u8, 1024) bytes_read, err2 := os.read(f, data) if err2 != nil { @@ -90,9 +97,9 @@ main :: proc() { execute_instruction(inst) } - if true { + if what_to_print == "registers" || what_to_print == "all" { print_reg :: proc(reg: Register) { - full := fmt.aprintf("%s (%s): %d ", reg.fullname, reg.bytename, reg.value.full) + full := fmt.aprintf("%s: %d ", reg.fullname, reg.value.full) hex := fmt.aprintf("0x%04x ", reg.value.full) fmt.printf("%s %*[1]s %s %*[4]s %08b %08b", full, 18 - len(full), "|", hex, 10 - len(hex), "|", reg.value.high, reg.value.low) @@ -105,7 +112,7 @@ main :: proc() { print_reg(reg) } } - if false { + if what_to_print == "instructions" || what_to_print == "all" { print_instructions_stdout(instructions_list[:]) } } diff --git a/test_registers.sh b/test_registers.sh index 22bbef5..6370c9f 100755 --- a/test_registers.sh +++ b/test_registers.sh @@ -16,7 +16,7 @@ odin build . -out:sim8086 for asm_txt in asm_files/*.txt; do asm_listing=$(basename $asm_txt .txt) - ./sim8086 asm_files/${asm_listing}.bin | awk '{print $1 ":" $5}' | sort > temp1 + ./sim8086 asm_files/${asm_listing}.bin registers | awk '{print $1 $4}' | sort > temp1 cat $asm_txt | awk '/Final registers/,0' | tail -n +2 | awk '{print $1 $2}' | sort > temp2 diff -U0 --color temp1 temp2 done diff --git a/types.odin b/types.odin index 310a491..c47ff2d 100644 --- a/types.odin +++ b/types.odin @@ -2,7 +2,6 @@ package sim_8086 Register :: struct { fullname: string, - bytename: string, value: struct #raw_union { using _: struct { low, high: byte, @@ -30,7 +29,16 @@ Displacement :: union { Disp16 } -RegisterId :: distinct u8 +RegisterAccess :: enum { + Low, + High, + Full, +} + +RegisterId :: struct { + access: RegisterAccess, + id: int, +} Immediate8 :: distinct i8 Immediate16 :: distinct i16 ImmediateU8 :: distinct u8