Fix register logic since we can access high and low parts, it's really ugly

This commit is contained in:
Joseph Ferano 2025-03-18 21:16:08 +07:00
parent b78d043b6c
commit c312b7fd57
7 changed files with 103 additions and 39 deletions

View File

@ -26,11 +26,11 @@ mov ds, bx
mov es, cx mov es, cx
mov al, 0x11 mov al, 0x11
mov bl, 0x33 mov bh, 0x33
mov cl, 0x55 mov cl, 0x55
mov dl, 0x77 mov dh, 0x77
mov al, bl mov ah, bl
mov cl, dh mov cl, dh
mov ss, ax mov ss, ax

View File

@ -11,18 +11,17 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
case .Register: case .Register:
reg: u8 reg: u8
switch inst.reg_info { switch inst.reg_info {
case .None: case .None: panic("Register is required but the encoded location is not provided")
panic("Register is required but the encoded location is not provided") case .FirstByteLast3: reg = data[0] & 0b111
case .FirstByteLast3: case .FirstByteMiddle3: reg = (data[0] >> 3) & 0b111
reg = data[0] & 0b111 case .SecondByteMiddle3: reg = (data[1] >> 3) & 0b111
case .FirstByteMiddle3: case .SecondByteLast3: reg = data[1] & 0b111
reg = (data[0] >> 3) & 0b111 }
case .SecondByteMiddle3: if word {
reg = (data[1] >> 3) & 0b111 operand = RegisterId { id = (int)(reg), access = .Full }
case .SecondByteLast3: } else {
reg = data[1] & 0b111 operand = RegisterId { id = (int)(reg % 4), access = reg < 4 ? .Low : .High }
} }
operand = (RegisterId)(registers[reg].code)
case .SegmentRegister: case .SegmentRegister:
reg: u8 reg: u8
switch inst.reg_info { 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:]) } op = MemoryAddr{ addr_id = rm , displacement = get_i16(data[2:]) }
processed^ += 2 processed^ += 2
} else if mod == 3 { } 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 operand = op
case .Immediate: case .Immediate:
@ -72,7 +75,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
operand = (ImmediateU8)(data[processed^]) operand = (ImmediateU8)(data[processed^])
processed^ += 1 processed^ += 1
case .Accumulator: case .Accumulator:
operand = (RegisterId)(registers[0].code) operand = RegisterId { id = 0, access = word ? .Full : .Low }
case .DirectAddress: case .DirectAddress:
operand = (DirectAddress)(get_i16(data[1:])) operand = (DirectAddress)(get_i16(data[1:]))
processed^ += 2 processed^ += 2

View File

@ -9,16 +9,51 @@ execute_instruction :: proc(inst: Instruction) {
#partial switch inst.opname { #partial switch inst.opname {
case .MOV: case .MOV:
if reg_id,ok := inst.dst.(RegisterId); ok { if reg_id,ok := inst.dst.(RegisterId); ok {
// val := registers[reg_id.id].value.full
#partial switch val in inst.src { #partial switch val in inst.src {
case Immediate8: 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: 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: case Immediate16:
registers[reg_id].value.full = (u16)(val) registers[reg_id.id].value.full = (u16)(val)
case RegisterId: 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)
} }
} }
} }

View File

@ -123,13 +123,24 @@ get_opname :: proc(inst: Instruction) -> (string, bool) {
return name, interseg 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 string_val: string
switch val in operand { switch val in operand {
case None: case None:
string_val = "" string_val = ""
case RegisterId: case RegisterId:
string_val = is_word ? registers[val].fullname : registers[val].bytename string_val = get_register_name(val)
case Immediate8, ImmediateU8, Immediate16, DirectWithinSegment: case Immediate8, ImmediateU8, Immediate16, DirectWithinSegment:
string_val = fmt.aprintf("%d", val) string_val = fmt.aprintf("%d", val)
case MemoryAddr: case MemoryAddr:
@ -147,7 +158,7 @@ get_operand_string :: proc(operand: Operand, is_word: bool, has_segment: Maybe(R
case VariablePort: case VariablePort:
string_val = variable_port.fullname string_val = variable_port.fullname
case ShiftRotate: case ShiftRotate:
string_val = val ? registers[1].bytename : "1" string_val = val ? "cl" : "1"
case Repeat: case Repeat:
string_val = (string)(val) string_val = (string)(val)
case Intersegment: case Intersegment:
@ -178,8 +189,8 @@ get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruct
fmt.sbprint(&instruction_builder, "lock ") fmt.sbprint(&instruction_builder, "lock ")
} }
dst_str := get_operand_string(inst.dst, inst.is_word, inst.has_segment) dst_str := get_operand_string(inst.dst, inst.has_segment)
src_str := get_operand_string(inst.src, inst.is_word, inst.has_segment) src_str := get_operand_string(inst.src, inst.has_segment)
opname: string opname: string
is_interseg: bool is_interseg: bool
if inst_info.check_second_encoding { if inst_info.check_second_encoding {

View File

@ -7,15 +7,20 @@ import "core:strings"
RIGHT_ALIGN_AMOUNT := 35 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 { registers := [8]Register {
{fullname = "ax", bytename = "al", code = 0b000}, {fullname = "ax", code = 0b000},
{fullname = "cx", bytename = "cl", code = 0b001}, {fullname = "cx", code = 0b001},
{fullname = "dx", bytename = "dl", code = 0b010}, {fullname = "dx", code = 0b010},
{fullname = "bx", bytename = "bl", code = 0b011}, {fullname = "bx", code = 0b011},
{fullname = "sp", bytename = "ah", code = 0b100}, {fullname = "sp", code = 0b100},
{fullname = "bp", bytename = "ch", code = 0b101}, {fullname = "bp", code = 0b101},
{fullname = "si", bytename = "dh", code = 0b110}, {fullname = "si", code = 0b110},
{fullname = "di", bytename = "bh", code = 0b111}, {fullname = "di", code = 0b111},
} }
segment_registers := [4]Register { segment_registers := [4]Register {
@ -69,6 +74,8 @@ main :: proc() {
} }
defer os.close(f) defer os.close(f)
what_to_print := len(os.args) >= 3 ? os.args[2] : ""
data := make([]u8, 1024) data := make([]u8, 1024)
bytes_read, err2 := os.read(f, data) bytes_read, err2 := os.read(f, data)
if err2 != nil { if err2 != nil {
@ -90,9 +97,9 @@ main :: proc() {
execute_instruction(inst) execute_instruction(inst)
} }
if true { if what_to_print == "registers" || what_to_print == "all" {
print_reg :: proc(reg: Register) { 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) hex := fmt.aprintf("0x%04x ", reg.value.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.value.high, reg.value.low)
@ -105,7 +112,7 @@ main :: proc() {
print_reg(reg) print_reg(reg)
} }
} }
if false { if what_to_print == "instructions" || what_to_print == "all" {
print_instructions_stdout(instructions_list[:]) print_instructions_stdout(instructions_list[:])
} }
} }

View File

@ -16,7 +16,7 @@ odin build . -out:sim8086
for asm_txt in asm_files/*.txt; for asm_txt in asm_files/*.txt;
do do
asm_listing=$(basename $asm_txt .txt) 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 cat $asm_txt | awk '/Final registers/,0' | tail -n +2 | awk '{print $1 $2}' | sort > temp2
diff -U0 --color temp1 temp2 diff -U0 --color temp1 temp2
done done

View File

@ -2,7 +2,6 @@ package sim_8086
Register :: struct { Register :: struct {
fullname: string, fullname: string,
bytename: string,
value: struct #raw_union { value: struct #raw_union {
using _: struct { using _: struct {
low, high: byte, low, high: byte,
@ -30,7 +29,16 @@ Displacement :: union {
Disp16 Disp16
} }
RegisterId :: distinct u8 RegisterAccess :: enum {
Low,
High,
Full,
}
RegisterId :: struct {
access: RegisterAccess,
id: int,
}
Immediate8 :: distinct i8 Immediate8 :: distinct i8
Immediate16 :: distinct i16 Immediate16 :: distinct i16
ImmediateU8 :: distinct u8 ImmediateU8 :: distinct u8