Fix register logic since we can access high and low parts, it's really ugly
This commit is contained in:
parent
b78d043b6c
commit
c312b7fd57
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
29
sim8086.odin
29
sim8086.odin
@ -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[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
12
types.odin
12
types.odin
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user