Use an enum to represent registers, parse txt files, check CPU state against expected
This commit is contained in:
		
							parent
							
								
									305ac557fa
								
							
						
					
					
						commit
						08874c4533
					
				@ -66,7 +66,7 @@ get_op :: proc(inst: Instruction) -> (Op, bool) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return op, interseg
 | 
					    return op, interseg
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, processed: ^int, word: bool, has_segreg: Maybe(Register)) -> Operand {
 | 
					parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, processed: ^int, word: bool, has_segreg: Maybe(RegisterId)) -> Operand {
 | 
				
			||||||
    operand: Operand = None{}
 | 
					    operand: Operand = None{}
 | 
				
			||||||
    switch opinfo {
 | 
					    switch opinfo {
 | 
				
			||||||
    case .None:
 | 
					    case .None:
 | 
				
			||||||
@ -80,11 +80,11 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
 | 
				
			|||||||
        case .SecondByteLast3:   reg = data[1] & 0b111
 | 
					        case .SecondByteLast3:   reg = data[1] & 0b111
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if opinfo == .SegmentRegister {
 | 
					        if opinfo == .SegmentRegister {
 | 
				
			||||||
            operand = (RegisterId){id = SEGMENT_REGISTER_START + (int)(reg), access = .Full}
 | 
					            operand = (RegisterId){idx = SEGMENT_REGISTER_START + (int)(reg), access = .Full}
 | 
				
			||||||
        } else if word {
 | 
					        } else if word {
 | 
				
			||||||
            operand = RegisterId { id = (int)(reg), access = .Full }
 | 
					            operand = RegisterId { idx = (int)(reg), access = .Full }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            operand = RegisterId { id = (int)(reg % 4), access = reg < 4 ? .Low : .High }
 | 
					            operand = RegisterId { idx = (int)(reg % 4), access = reg < 4 ? .Low : .High }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case .RegisterMemory:
 | 
					    case .RegisterMemory:
 | 
				
			||||||
        mod := data[1] >> 6
 | 
					        mod := data[1] >> 6
 | 
				
			||||||
@ -107,9 +107,9 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
 | 
				
			|||||||
            processed^ += 2
 | 
					            processed^ += 2
 | 
				
			||||||
        } else if mod == 3 {
 | 
					        } else if mod == 3 {
 | 
				
			||||||
            if word {
 | 
					            if word {
 | 
				
			||||||
                op = RegisterId { id = (int)(rm), access = .Full }
 | 
					                op = RegisterId { idx = (int)(rm), access = .Full }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                op = RegisterId { id = (int)(rm % 4), access = rm < 4 ? .Low : .High }
 | 
					                op = RegisterId { idx = (int)(rm % 4), access = rm < 4 ? .Low : .High }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        operand = op
 | 
					        operand = op
 | 
				
			||||||
@ -126,7 +126,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
 | 
				
			|||||||
        operand = Immediate { value = u16(data[processed^]), size = .Unsigned8 }
 | 
					        operand = Immediate { value = u16(data[processed^]), size = .Unsigned8 }
 | 
				
			||||||
        processed^ += 1
 | 
					        processed^ += 1
 | 
				
			||||||
    case .Accumulator:
 | 
					    case .Accumulator:
 | 
				
			||||||
        operand = RegisterId { id = 0, access = word ? .Full : .Low }
 | 
					        operand = RegisterId { idx = 0, access = word ? .Full : .Low }
 | 
				
			||||||
    case .DirectAddress:
 | 
					    case .DirectAddress:
 | 
				
			||||||
        // operand = DirectAddress { value = get_i16(data[1:]) }
 | 
					        // operand = DirectAddress { value = get_i16(data[1:]) }
 | 
				
			||||||
        operand = (DirectAddress)(get_i16(data[1:]))
 | 
					        operand = (DirectAddress)(get_i16(data[1:]))
 | 
				
			||||||
@ -136,10 +136,10 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
 | 
				
			|||||||
        // NOTE: In order to mimic the label offset, you have to take the value you got and add two
 | 
					        // NOTE: In order to mimic the label offset, you have to take the value you got and add two
 | 
				
			||||||
        operand = (Jump)((i8)(data[1]) + 2)
 | 
					        operand = (Jump)((i8)(data[1]) + 2)
 | 
				
			||||||
    case .VariablePort:
 | 
					    case .VariablePort:
 | 
				
			||||||
        operand = RegisterId { id = (int)(variable_port.code), access = .Full }
 | 
					        operand = RegisterId { idx = (int)(Register.dx), access = .Full }
 | 
				
			||||||
    case .ShiftRotate:
 | 
					    case .ShiftRotate:
 | 
				
			||||||
        v_flag := data[0] & 0b10 != 0
 | 
					        v_flag := data[0] & 0b10 != 0
 | 
				
			||||||
        operand = v_flag ? RegisterId { id = 1, access = .Low } : Immediate { value = 1 }
 | 
					        operand = v_flag ? RegisterId { idx = 1, access = .Low } : Immediate { value = 1 }
 | 
				
			||||||
    case .Repeat:
 | 
					    case .Repeat:
 | 
				
			||||||
        bits := (data[1] & 0b1110) >> 1
 | 
					        bits := (data[1] & 0b1110) >> 1
 | 
				
			||||||
        w := (data[1] & 0b1) == 1 ? "w" : "b"
 | 
					        w := (data[1] & 0b1) == 1 ? "w" : "b"
 | 
				
			||||||
@ -169,7 +169,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read: int) {
 | 
					decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read: int) {
 | 
				
			||||||
    idx := 0
 | 
					    idx := 0
 | 
				
			||||||
    has_segment: Maybe(Register)
 | 
					    has_segment: Maybe(RegisterId)
 | 
				
			||||||
    has_lock: bool
 | 
					    has_lock: bool
 | 
				
			||||||
    for idx < bytes_to_read {
 | 
					    for idx < bytes_to_read {
 | 
				
			||||||
        instruction: Instruction
 | 
					        instruction: Instruction
 | 
				
			||||||
@ -203,7 +203,7 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
 | 
				
			|||||||
            continue
 | 
					            continue
 | 
				
			||||||
        } else if inst.opname == .SEGMENT {
 | 
					        } else if inst.opname == .SEGMENT {
 | 
				
			||||||
            reg := (curr_byte & 0b11000) >> 3
 | 
					            reg := (curr_byte & 0b11000) >> 3
 | 
				
			||||||
            has_segment = CPU.registers[SEGMENT_REGISTER_START+reg]
 | 
					            has_segment = RegisterId { idx = int(SEGMENT_REGISTER_START+reg) }
 | 
				
			||||||
            idx += 1
 | 
					            idx += 1
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        } else if inst.opname == .AAM {
 | 
					        } else if inst.opname == .AAM {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,34 +4,40 @@ import "core:os"
 | 
				
			|||||||
import "core:fmt"
 | 
					import "core:fmt"
 | 
				
			||||||
import "core:math"
 | 
					import "core:math"
 | 
				
			||||||
import "core:strings"
 | 
					import "core:strings"
 | 
				
			||||||
 | 
					import "core:reflect"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
get_operand_value :: proc(operand: Operand) -> u16 {
 | 
					get_operand_value :: proc(operand: Operand) -> u16 {
 | 
				
			||||||
    #partial switch opr in operand {
 | 
					    #partial switch opr in operand {
 | 
				
			||||||
    case Immediate:
 | 
					    case Immediate:
 | 
				
			||||||
        return opr.value
 | 
					        return opr.value
 | 
				
			||||||
    case RegisterId:
 | 
					    case RegisterId:
 | 
				
			||||||
 | 
					        reg_val := CPU.registers[opr.idx]
 | 
				
			||||||
        switch opr.access {
 | 
					        switch opr.access {
 | 
				
			||||||
        case .Low, .High:
 | 
					        case .Low, .High:
 | 
				
			||||||
            val := opr.access == .Low ? CPU.registers[opr.id].value.low : CPU.registers[opr.id].value.high
 | 
					            return u16(opr.access == .Low ? reg_val.low : reg_val.high)
 | 
				
			||||||
            return u16(val)
 | 
					 | 
				
			||||||
        case .Full:
 | 
					        case .Full:
 | 
				
			||||||
            return CPU.registers[opr.id].value.full
 | 
					            return reg_val.full
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return 0
 | 
					    return 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set_register_value :: proc(reg_id: RegisterId, value: u16) {
 | 
					set_register_value :: proc(reg: RegisterId, value: u16) {
 | 
				
			||||||
    switch reg_id.access {
 | 
					    switch reg.access {
 | 
				
			||||||
    case .Low:
 | 
					    case .Low:
 | 
				
			||||||
        CPU.registers[reg_id.id].value.low = u8(value)
 | 
					        CPU.registers[reg.idx].low = u8(value)
 | 
				
			||||||
    case .High:
 | 
					    case .High:
 | 
				
			||||||
        CPU.registers[reg_id.id].value.high = u8(value)
 | 
					        CPU.registers[reg.idx].high = u8(value)
 | 
				
			||||||
    case .Full:
 | 
					    case .Full:
 | 
				
			||||||
        CPU.registers[reg_id.id].value.full = u16(value)
 | 
					        CPU.registers[reg.idx].full = u16(value)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue {
 | 
				
			||||||
 | 
					    reg,_ := reflect.enum_from_name(Register, name)
 | 
				
			||||||
 | 
					    return &cpu.registers[int(reg)]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
check_zero_flag :: proc(value: u16) {
 | 
					check_zero_flag :: proc(value: u16) {
 | 
				
			||||||
    CPU.flags.ZF = value == 0
 | 
					    CPU.flags.ZF = value == 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -48,19 +54,19 @@ execute_instruction :: proc(inst: Instruction) {
 | 
				
			|||||||
            set_register_value(reg, src_val)
 | 
					            set_register_value(reg, src_val)
 | 
				
			||||||
        case .ADD:
 | 
					        case .ADD:
 | 
				
			||||||
            src_val := get_operand_value(inst.src)
 | 
					            src_val := get_operand_value(inst.src)
 | 
				
			||||||
            val := CPU.registers[reg.id].value.full + src_val
 | 
					            val := CPU.registers[reg.idx].full + src_val
 | 
				
			||||||
            set_register_value(reg, val)
 | 
					            set_register_value(reg, val)
 | 
				
			||||||
            check_zero_flag(val)
 | 
					            check_zero_flag(val)
 | 
				
			||||||
            check_sign_flag(val)
 | 
					            check_sign_flag(val)
 | 
				
			||||||
        case .SUB:
 | 
					        case .SUB:
 | 
				
			||||||
            src_val := get_operand_value(inst.src)
 | 
					            src_val := get_operand_value(inst.src)
 | 
				
			||||||
            val := CPU.registers[reg.id].value.full - src_val
 | 
					            val := CPU.registers[reg.idx].full - src_val
 | 
				
			||||||
            set_register_value(reg, val)
 | 
					            set_register_value(reg, val)
 | 
				
			||||||
            check_zero_flag(val)
 | 
					            check_zero_flag(val)
 | 
				
			||||||
            check_sign_flag(val)
 | 
					            check_sign_flag(val)
 | 
				
			||||||
        case .CMP:
 | 
					        case .CMP:
 | 
				
			||||||
            src_val := get_operand_value(inst.src)
 | 
					            src_val := get_operand_value(inst.src)
 | 
				
			||||||
            val := CPU.registers[reg.id].value.full - src_val
 | 
					            val := CPU.registers[reg.idx].full - src_val
 | 
				
			||||||
            check_zero_flag(val)
 | 
					            check_zero_flag(val)
 | 
				
			||||||
            check_sign_flag(val)
 | 
					            check_sign_flag(val)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -37,7 +37,7 @@ calculate_effective_address :: proc(r_m: u8) -> string {
 | 
				
			|||||||
    return val
 | 
					    return val
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
get_memory_string :: proc(memoryAddr: MemoryAddr, has_segment: Maybe(Register)) -> string {
 | 
					get_memory_string :: proc(memoryAddr: MemoryAddr, has_segment: Maybe(RegisterId)) -> string {
 | 
				
			||||||
    disp: string
 | 
					    disp: string
 | 
				
			||||||
    switch value in memoryAddr.displacement {
 | 
					    switch value in memoryAddr.displacement {
 | 
				
			||||||
    case None:
 | 
					    case None:
 | 
				
			||||||
@ -53,7 +53,7 @@ get_memory_string :: proc(memoryAddr: MemoryAddr, has_segment: Maybe(Register))
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    seg_string: string
 | 
					    seg_string: string
 | 
				
			||||||
    if segreg, ok := has_segment.?; ok {
 | 
					    if segreg, ok := has_segment.?; ok {
 | 
				
			||||||
        seg_string = fmt.aprintf("%s:", segreg.fullname)
 | 
					        seg_string = fmt.aprintf("%s:", get_register_name(segreg))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    text := fmt.aprintf("%s[%s%s]", seg_string, calculate_effective_address(memoryAddr.addr_id), disp)
 | 
					    text := fmt.aprintf("%s[%s%s]", seg_string, calculate_effective_address(memoryAddr.addr_id), disp)
 | 
				
			||||||
    return text
 | 
					    return text
 | 
				
			||||||
@ -78,14 +78,14 @@ get_register_name :: proc(reg_id: RegisterId) -> string {
 | 
				
			|||||||
    low_names := [?]string{"al", "cl", "dl", "bl"}
 | 
					    low_names := [?]string{"al", "cl", "dl", "bl"}
 | 
				
			||||||
    high_names := [?]string{"ah", "ch", "dh", "bh"}
 | 
					    high_names := [?]string{"ah", "ch", "dh", "bh"}
 | 
				
			||||||
    switch reg_id.access {
 | 
					    switch reg_id.access {
 | 
				
			||||||
    case .Full: return CPU.registers[reg_id.id].fullname
 | 
					    case .Full: return reflect.enum_string(Register(reg_id.idx))
 | 
				
			||||||
    case .Low: return low_names[reg_id.id]
 | 
					    case .Low: return low_names[reg_id.idx]
 | 
				
			||||||
    case .High: return high_names[reg_id.id % 4]
 | 
					    case .High: return high_names[reg_id.idx % 4]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ""
 | 
					    return ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
get_operand_string :: proc(operand: Operand, has_segment: Maybe(Register)) -> string {
 | 
					get_operand_string :: proc(operand: Operand, has_segment: Maybe(RegisterId)) -> string {
 | 
				
			||||||
    string_val: string
 | 
					    string_val: string
 | 
				
			||||||
    switch val in operand {
 | 
					    switch val in operand {
 | 
				
			||||||
    case None:
 | 
					    case None:
 | 
				
			||||||
@ -106,7 +106,7 @@ get_operand_string :: proc(operand: Operand, has_segment: Maybe(Register)) -> st
 | 
				
			|||||||
    case DirectAddress:
 | 
					    case DirectAddress:
 | 
				
			||||||
        seg_string: string
 | 
					        seg_string: string
 | 
				
			||||||
        if segreg, ok := has_segment.?; ok {
 | 
					        if segreg, ok := has_segment.?; ok {
 | 
				
			||||||
            seg_string = fmt.aprintf("%s:", segreg.fullname)
 | 
					            seg_string = fmt.aprintf("%s:", get_register_name(segreg))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        string_val = fmt.aprintf("%s[%d]", seg_string, val)
 | 
					        string_val = fmt.aprintf("%s[%d]", seg_string, val)
 | 
				
			||||||
    case Jump:
 | 
					    case Jump:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										44
									
								
								sim8086.odin
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								sim8086.odin
									
									
									
									
									
								
							@ -1,32 +1,15 @@
 | 
				
			|||||||
package sim_8086
 | 
					package sim_8086
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "core:os"
 | 
					import "core:os"
 | 
				
			||||||
import "core:path"
 | 
					import path "core:path/filepath"
 | 
				
			||||||
import "core:fmt"
 | 
					import "core:fmt"
 | 
				
			||||||
import "core:math"
 | 
					import "core:math"
 | 
				
			||||||
import "core:strings"
 | 
					import "core:strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CPU := Cpu {
 | 
					CPU := Cpu {
 | 
				
			||||||
    registers = [12]Register {
 | 
					 | 
				
			||||||
        {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},
 | 
					 | 
				
			||||||
        {fullname = "es", code = 0b000},
 | 
					 | 
				
			||||||
        {fullname = "cs", code = 0b001},
 | 
					 | 
				
			||||||
        {fullname = "ss", code = 0b010},
 | 
					 | 
				
			||||||
        {fullname = "ds", code = 0b011},
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    memory = make([dynamic]u8, 65536),
 | 
					    memory = make([dynamic]u8, 65536),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
variable_port := CPU.registers[2]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
main :: proc() {
 | 
					main :: proc() {
 | 
				
			||||||
    f,err := os.open(os.args[1])
 | 
					    f,err := os.open(os.args[1])
 | 
				
			||||||
    if err != os.ERROR_NONE {
 | 
					    if err != os.ERROR_NONE {
 | 
				
			||||||
@ -59,22 +42,23 @@ main :: proc() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if what_to_print == "registers" || what_to_print == "all" {
 | 
					    if what_to_print == "registers" || what_to_print == "all" {
 | 
				
			||||||
        print_reg :: proc(reg: Register) {
 | 
					        for reg,i in CPU.registers {
 | 
				
			||||||
            full := fmt.aprintf("%s: %d ", reg.fullname, reg.value.full)
 | 
					            full := fmt.aprintf("%s: %d ", get_register_name(RegisterId{idx=i}), reg.full)
 | 
				
			||||||
            hex := fmt.aprintf("0x%04x ", reg.value.full)
 | 
					            hex := fmt.aprintf("0x%04x ", reg.full)
 | 
				
			||||||
            fmt.printf("%s %*[1]s %s %*[4]s %08b %08b",
 | 
					            fmt.printf("%s %*[1]s %s %*[4]s %08b %08b",
 | 
				
			||||||
                       full, 18 - len(full), "|", hex, 10 - len(hex), "|", reg.value.high, reg.value.low)
 | 
					                       full, 18 - len(full), "|", hex, 10 - len(hex), "|", reg.high, reg.low)
 | 
				
			||||||
            fmt.println()
 | 
					            fmt.println()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        for reg in CPU.registers {
 | 
					 | 
				
			||||||
            print_reg(reg)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // fmt.println("Checking Against Expected State")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // fmt.println(os.args[1])
 | 
					        path,ok := strings.replace(os.args[1], ".bin", ".txt", 1)
 | 
				
			||||||
        // path := path.base_no_ext(os.args[1])
 | 
					        expected_cpu,_ := extract_expected_cpu_state(path)
 | 
				
			||||||
        // fmt.println(path)
 | 
					        for reg,i in expected_cpu.registers {
 | 
				
			||||||
        // extract_expected_cpu_state(path)
 | 
					            if CPU.registers[i].full != reg.full {
 | 
				
			||||||
 | 
					                name := get_register_name(RegisterId{idx=i})
 | 
				
			||||||
 | 
					                msg := "%s register does not match - Expected %04x | Actual %04x"
 | 
				
			||||||
 | 
					                fmt.eprintfln(msg, name, reg.full, CPU.registers[i].full)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if what_to_print == "instructions" || what_to_print == "all" {
 | 
					    if what_to_print == "instructions" || what_to_print == "all" {
 | 
				
			||||||
        print_instructions_stdout(instructions_list[:])
 | 
					        print_instructions_stdout(instructions_list[:])
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										54
									
								
								testing.odin
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								testing.odin
									
									
									
									
									
								
							@ -4,35 +4,41 @@ import "core:os"
 | 
				
			|||||||
import "core:fmt"
 | 
					import "core:fmt"
 | 
				
			||||||
import "core:math"
 | 
					import "core:math"
 | 
				
			||||||
import "core:strings"
 | 
					import "core:strings"
 | 
				
			||||||
import "core:text/regex"
 | 
					import "core:strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extract_expected_cpu_state :: proc(listing_num: int) -> (Cpu, bool) {
 | 
					extract_expected_cpu_state :: proc(filename: string) -> (Cpu, bool) {
 | 
				
			||||||
    cpu: Cpu
 | 
					    cpu: Cpu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // filename := fmt.aprintf("./asm_files/list-%04d.txt", listing_num)
 | 
					    data,ok := os.read_entire_file(filename)
 | 
				
			||||||
    // fmt.println(filename)
 | 
					    if !ok {
 | 
				
			||||||
    // data,ok := os.read_entire_file(filename)
 | 
					        return cpu, false
 | 
				
			||||||
    // if !ok {
 | 
					    }
 | 
				
			||||||
    //     return cpu, false
 | 
					    defer delete(data)
 | 
				
			||||||
    // }
 | 
					 | 
				
			||||||
    // defer delete(data)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // content := string(data)
 | 
					    content := string(data)
 | 
				
			||||||
    // lines := strings.split(content, "\n")
 | 
					    lines := strings.split(content, "\n")
 | 
				
			||||||
    // defer delete(lines)
 | 
					    defer delete(lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // for line in lines {
 | 
					    for line in lines {
 | 
				
			||||||
    //     for c in line {
 | 
					        space_count := 0
 | 
				
			||||||
    //         if c != ' ' {
 | 
					        for c,i in line {
 | 
				
			||||||
    //             continue
 | 
					            if space_count == 0  && c != ' ' {
 | 
				
			||||||
    //         } else {
 | 
					                break
 | 
				
			||||||
    //             fmt.print(c)
 | 
					            } else if c == ' ' {
 | 
				
			||||||
    //         }
 | 
					                space_count += 1
 | 
				
			||||||
    //     }
 | 
					            } else {
 | 
				
			||||||
    //     fmt.println()
 | 
					                if line[i:i+5] != "flags" {
 | 
				
			||||||
    // }
 | 
					                    reg_name := line[i:i+2]
 | 
				
			||||||
 | 
					                    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 {
 | 
				
			||||||
 | 
					                        reg_value^.full = u16(hex_num)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // cpu.registers[]
 | 
					 | 
				
			||||||
    return cpu, true
 | 
					    return cpu, true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								types.odin
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								types.odin
									
									
									
									
									
								
							@ -1,14 +1,25 @@
 | 
				
			|||||||
package sim_8086
 | 
					package sim_8086
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Register :: struct {
 | 
					Register :: enum {
 | 
				
			||||||
    fullname: string,
 | 
					    ax,
 | 
				
			||||||
    value: struct #raw_union {
 | 
					    cx,
 | 
				
			||||||
        using _: struct {
 | 
					    dx,
 | 
				
			||||||
            low, high: byte,
 | 
					    bx,
 | 
				
			||||||
        },
 | 
					    sp,
 | 
				
			||||||
        full: u16,
 | 
					    bp,
 | 
				
			||||||
 | 
					    si,
 | 
				
			||||||
 | 
					    di,
 | 
				
			||||||
 | 
					    es,
 | 
				
			||||||
 | 
					    cs,
 | 
				
			||||||
 | 
					    ss,
 | 
				
			||||||
 | 
					    ds,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RegisterValue :: struct #raw_union {
 | 
				
			||||||
 | 
					    using _: struct {
 | 
				
			||||||
 | 
					        low, high: byte,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    code: u8,
 | 
					    full: u16,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Flags :: struct {
 | 
					Flags :: struct {
 | 
				
			||||||
@ -34,14 +45,14 @@ Displacement :: union {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RegisterAccess :: enum {
 | 
					RegisterAccess :: enum {
 | 
				
			||||||
 | 
					    Full,
 | 
				
			||||||
    Low,
 | 
					    Low,
 | 
				
			||||||
    High,
 | 
					    High,
 | 
				
			||||||
    Full,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RegisterId :: struct {
 | 
					RegisterId :: struct {
 | 
				
			||||||
 | 
					    idx: int,
 | 
				
			||||||
    access: RegisterAccess,
 | 
					    access: RegisterAccess,
 | 
				
			||||||
    id: int,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ImmediateSize :: enum {
 | 
					ImmediateSize :: enum {
 | 
				
			||||||
    Signed8,
 | 
					    Signed8,
 | 
				
			||||||
@ -125,7 +136,7 @@ Instruction :: struct {
 | 
				
			|||||||
    indirect_intersegment: bool,
 | 
					    indirect_intersegment: bool,
 | 
				
			||||||
    // TODO: This is trickier than I thought, it's more than just the one instruction
 | 
					    // TODO: This is trickier than I thought, it's more than just the one instruction
 | 
				
			||||||
    // that uses it
 | 
					    // that uses it
 | 
				
			||||||
    has_segment: Maybe(Register),
 | 
					    has_segment: Maybe(RegisterId),
 | 
				
			||||||
    has_lock: bool,
 | 
					    has_lock: bool,
 | 
				
			||||||
    bytes_read: int,
 | 
					    bytes_read: int,
 | 
				
			||||||
    raw_data: []u8,
 | 
					    raw_data: []u8,
 | 
				
			||||||
@ -134,7 +145,7 @@ Instruction :: struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Cpu :: struct {
 | 
					Cpu :: struct {
 | 
				
			||||||
    flags: Flags,
 | 
					    flags: Flags,
 | 
				
			||||||
    registers: [12]Register,
 | 
					    registers: [12]RegisterValue,
 | 
				
			||||||
    memory: [dynamic]u8,
 | 
					    memory: [dynamic]u8,
 | 
				
			||||||
    total_bytes_processed: int
 | 
					    total_bytes_processed: int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user