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 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

View File

@ -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

View File

@ -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)
case ImmediateU8:
registers[reg_id].value.low = (u8)(val)
case Immediate16:
registers[reg_id].value.full = (u16)(val)
case RegisterId:
registers[reg_id].value.full = registers[val].value.full
if reg_id.access == .Low {
registers[reg_id.id].value.low = (u8)(val)
} else {
registers[reg_id.id].value.high = (u8)(val)
}
case ImmediateU8:
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.id].value.full = (u16)(val)
case RegisterId:
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
}
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 {

View File

@ -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[:])
}
}

View File

@ -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

View File

@ -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