From 831a307975cb40f997d54ee5679f7d56e21c6bfe Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 22 Mar 2025 15:21:47 +0700 Subject: [PATCH] Fix and simplify (delete) all the signage stuff --- decoding.odin | 16 ++++++++-------- execution.odin | 7 ++++--- printing.odin | 19 +++---------------- sim8086.odin | 11 +++++++++-- testing.odin | 10 +--------- types.odin | 9 +++------ 6 files changed, 28 insertions(+), 44 deletions(-) diff --git a/decoding.odin b/decoding.odin index 644b616..91805d0 100644 --- a/decoding.odin +++ b/decoding.odin @@ -102,10 +102,13 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr op = MemoryAddr{ addr_id = rm } } } else if mod == 1 { - op = MemoryAddr{ addr_id = rm , displacement_value = (i16)(data[2]) , displacement_size = .Signed8 } + // NOTE: Per the 8086 manual in order to detect signed displacement, you have + // to sign extend a byte to a word. In Odin like in other languages, first + // cast to an i8, before casting to an i16 and it'll sign extend + op = MemoryAddr{ addr_id = rm , displacement = i16(i8(data[2])) } processed^ += 1 } else if mod == 2 { - op = MemoryAddr{ addr_id = rm , displacement_value = get_i16(data[2:]) , displacement_size = .Signed16 } + op = MemoryAddr{ addr_id = rm , displacement = get_i16(data[2:]) } processed^ += 2 } else if mod == 3 { if word { @@ -122,11 +125,8 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr word_signed &&= data[0] & 0b0000_0010 == 0 } value: i16 = word_signed ? get_i16(data[data_idx:]) : i16(i8(data[data_idx])) - operand = Immediate { value = value, size = word_signed ? .Signed16 : .Signed8 } + operand = Immediate { value = value, size = word_signed ? ._16 : ._8 } processed^ += word_signed ? 2 : 1 - case .ImmediateUnsigned: - operand = Immediate { value = i16(data[processed^]), size = .Unsigned8 } - processed^ += 1 case .Accumulator: operand = RegisterId { name = .ax, access = word ? .Full : .Low } case .DirectAddress: @@ -148,7 +148,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr } case .ShiftRotate: v_flag := data[0] & 0b10 != 0 - operand = v_flag ? RegisterId { name = Register(1), access = .Low } : Immediate { value = 1 } + operand = v_flag ? RegisterId { name = .cx, access = .Low } : Immediate { value = 1 } case .Repeat: bits := (data[1] & 0b1110) >> 1 w := (data[1] & 0b1) == 1 ? "w" : "b" @@ -164,7 +164,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr processed^ += 1 case .DirectWithinSegment: value := (int)(get_i16(data[1:])) + total_bytes_processed + 3 - operand = Immediate { value = i16(value), size = .Signed16 } + operand = Immediate { value = i16(value), size = ._16 } processed^ += 2 case .Intersegment: operand = Intersegment { diff --git a/execution.odin b/execution.odin index 4cbb5ce..e8ba329 100644 --- a/execution.odin +++ b/execution.odin @@ -5,6 +5,7 @@ import "core:fmt" import "core:math" import "core:strings" import "core:reflect" +import "core:strconv" get_ip :: proc(cpu: ^Cpu) -> int { return int(cpu.registers[.ip].full) } @@ -38,7 +39,7 @@ get_operand_value :: proc(cpu: ^Cpu, operand: Operand) -> i16 { value := i16(u16(cpu.memory[opr+1] << 8) | u16(cpu.memory[opr])) return value case MemoryAddr: - idx := get_effective_address_value(cpu, opr.addr_id) + opr.displacement_value + idx := get_effective_address_value(cpu, opr.addr_id) + opr.displacement value := i16(u16(cpu.memory[idx+1] << 8) | u16(cpu.memory[idx])) // fmt.println("Checking", idx) // for i in 0..<6 { @@ -136,7 +137,7 @@ execute_instruction :: proc(cpu: ^Cpu, inst: Instruction) { #partial switch inst.opname { case .MOV: if imm,ok := inst.src.(Immediate); ok { - if imm.size == .Signed16 { + if imm.size == ._16 { cpu.memory[addr] = u8(imm.value & 0x00FF) cpu.memory[addr+1] = u8((u16(imm.value) & 0xFF00) >> 8) } else { @@ -150,7 +151,7 @@ execute_instruction :: proc(cpu: ^Cpu, inst: Instruction) { value := get_operand_value(cpu, inst.src) effective_addr_val := get_effective_address_value(cpu, mem_addr.addr_id) - addr := effective_addr_val + mem_addr.displacement_value + addr := effective_addr_val + mem_addr.displacement cpu.memory[addr] = u8(value & 0x00FF) cpu.memory[addr+1] = u8((u16(value) & 0xFF00) >> 8) diff --git a/printing.odin b/printing.odin index f86979b..6b66340 100644 --- a/printing.odin +++ b/printing.odin @@ -39,7 +39,7 @@ calculate_effective_address :: proc(r_m: u8) -> string { get_memory_string :: proc(memoryAddr: MemoryAddr, has_segment: Maybe(RegisterId)) -> string { disp: string - value := memoryAddr.displacement_value + value := memoryAddr.displacement if value != 0 { disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value)) } @@ -70,14 +70,7 @@ get_operand_string :: proc(operand: Operand, has_segment: Maybe(RegisterId)) -> 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)) - } + string_val = fmt.aprintf("%d", i16(val.value)) case MemoryAddr: string_val = get_memory_string(val, has_segment) case DirectAddress: @@ -132,13 +125,7 @@ get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruct } 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) - } + fmt.sbprintf(&instruction_builder, "%s %s%s, %s", opname, size_string, dst_str, src_str) } // Prepare padding and comment to add debug info diff --git a/sim8086.odin b/sim8086.odin index 36420c1..ab2c701 100644 --- a/sim8086.odin +++ b/sim8086.odin @@ -6,6 +6,7 @@ import "core:fmt" import "core:math" import "core:strings" import "core:reflect" +import "core:strconv" main :: proc() { f,err := os.open(os.args[1]) @@ -47,7 +48,12 @@ main :: proc() { memory = make([dynamic]u8, 1024 * 1024), // 1,048,576 } - execute_instructions(&cpu, decoded_insts) + num_idx := strings.last_index(os.args[1], "list-") + 5 + if listing_num,ok := strconv.parse_int(os.args[1][num_idx:num_idx+4]); ok { + if listing_num > 42 { + execute_instructions(&cpu, decoded_insts) + } + } if what_to_print == "registers" || what_to_print == "all" { fmt.println("Registers") @@ -66,8 +72,9 @@ main :: proc() { failed_ref: bool path,ok := strings.replace(os.args[1], ".bin", ".txt", 1) - ref_cpu,_ := extract_reference_cpu_state(path) + ref_cpu,_ := parse_reference_cpu_state(path) for reg_val,name in ref_cpu.registers { + if name == .ip && reg_val.full == 0 do continue if cpu.registers[name].full != reg_val.full { msg := "%s register does not match reference - Expected 0x%04x | Actual 0x%04x" fmt.printfln(msg, name, reg_val.full, cpu.registers[name].full) diff --git a/testing.odin b/testing.odin index 581ea2b..4ca3aff 100644 --- a/testing.odin +++ b/testing.odin @@ -7,7 +7,7 @@ import "core:strings" import "core:strconv" import "core:reflect" -extract_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) { +parse_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) { cpu: Cpu data,ok := os.read_entire_file(filename) @@ -20,7 +20,6 @@ extract_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) { lines := strings.split(content, "\n") defer delete(lines) - ignore_ip_reg := true for line in lines { space_count := 0 for c,i in line { @@ -42,9 +41,6 @@ extract_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) { } } else { reg_name := line[i:i+2] - if reg_name == "ip" { - ignore_ip_reg = false - } reg_value := get_cpu_register_by_name(&cpu, reg_name) hex_string := line[i+6:i+10] if hex_num,ok := strconv.parse_int(hex_string, 16); ok { @@ -56,9 +52,5 @@ extract_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) { } } - if ignore_ip_reg { - cpu.registers[.ip] = cpu.registers[.ip] - } - return cpu, true } diff --git a/types.odin b/types.odin index a2fe09d..fb0bfbf 100644 --- a/types.odin +++ b/types.odin @@ -58,9 +58,8 @@ RegisterId :: struct { access: RegisterAccess, } ImmediateSize :: enum { - Signed8, - Unsigned8, - Signed16, + _8, + _16, } Immediate :: struct { value: i16, @@ -68,8 +67,7 @@ Immediate :: struct { } MemoryAddr :: struct { addr_id: u8, - displacement_value: i16, - displacement_size: ImmediateSize, + displacement: i16, } DirectAddress :: distinct i16 Jump :: distinct i8 @@ -96,7 +94,6 @@ OperandInfo :: enum { SegmentRegister, RegisterMemory, Immediate, - ImmediateUnsigned, Accumulator, DirectAddress, Jump,