Clean up operand code by removing unnecessary variants

This commit is contained in:
Joseph Ferano 2025-03-19 18:57:34 +07:00
parent c312b7fd57
commit a91c3d9ba9
6 changed files with 50 additions and 85 deletions

View File

@ -8,7 +8,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
operand: Operand = None{} operand: Operand = None{}
switch opinfo { switch opinfo {
case .None: case .None:
case .Register: case .Register, .SegmentRegister:
reg: u8 reg: u8
switch inst.reg_info { switch inst.reg_info {
case .None: panic("Register is required but the encoded location is not provided") case .None: panic("Register is required but the encoded location is not provided")
@ -17,26 +17,13 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
case .SecondByteMiddle3: reg = (data[1] >> 3) & 0b111 case .SecondByteMiddle3: reg = (data[1] >> 3) & 0b111
case .SecondByteLast3: reg = data[1] & 0b111 case .SecondByteLast3: reg = data[1] & 0b111
} }
if word { if opinfo == .SegmentRegister {
operand = (RegisterId){id = SEGMENT_REGISTER_START + (int)(reg), access = .Full}
} else if word {
operand = RegisterId { id = (int)(reg), access = .Full } operand = RegisterId { id = (int)(reg), access = .Full }
} else { } else {
operand = RegisterId { id = (int)(reg % 4), access = reg < 4 ? .Low : .High } operand = RegisterId { id = (int)(reg % 4), access = reg < 4 ? .Low : .High }
} }
case .SegmentRegister:
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
}
operand = (SegmentRegister)(segment_registers[reg].code)
case .RegisterMemory: case .RegisterMemory:
mod := data[1] >> 6 mod := data[1] >> 6
rm := data[1] & 0b111 rm := data[1] & 0b111
@ -44,6 +31,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
op: Operand op: Operand
if mod == 0 { if mod == 0 {
if rm == 0b110 { if rm == 0b110 {
// op = DirectAddress { value = get_i16(data[2:]) }
op = (DirectAddress)(get_i16(data[2:])) op = (DirectAddress)(get_i16(data[2:]))
processed^ += 2 processed^ += 2
} else { } else {
@ -69,14 +57,16 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
if inst.has_sign_extension { if inst.has_sign_extension {
word_signed &&= data[0] & 0b0000_0010 == 0 word_signed &&= data[0] & 0b0000_0010 == 0
} }
operand = (Operand)(word_signed ? (Immediate16)(get_i16(data[data_idx:])) : (Immediate8)(data[data_idx])) value: u16 = word_signed ? u16(get_i16(data[data_idx:])) : u16(data[data_idx])
operand = Immediate { value = value, size = word_signed ? .Signed16 : .Signed8 }
processed^ += word_signed ? 2 : 1 processed^ += word_signed ? 2 : 1
case .ImmediateUnsigned: case .ImmediateUnsigned:
operand = (ImmediateU8)(data[processed^]) 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 { id = 0, access = word ? .Full : .Low }
case .DirectAddress: case .DirectAddress:
// operand = DirectAddress { value = get_i16(data[1:]) }
operand = (DirectAddress)(get_i16(data[1:])) operand = (DirectAddress)(get_i16(data[1:]))
processed^ += 2 processed^ += 2
case .Jump: case .Jump:
@ -84,16 +74,16 @@ 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 = VariablePort{} operand = RegisterId { id = (int)(variable_port.code), access = .Full }
case .ShiftRotate: case .ShiftRotate:
v_flag := data[0] & 0b10 != 0 v_flag := data[0] & 0b10 != 0
operand = (ShiftRotate)(v_flag) operand = v_flag ? RegisterId { id = 1, access = .Low } : Immediate { value = 1 }
case .Repeat: case .Repeat:
operand = get_repeat_op(data[1]) operand = get_repeat_op(data[1])
processed^ += 1 processed^ += 1
case .DirectWithinSegment: case .DirectWithinSegment:
value := (int)(get_i16(data[1:])) + total_bytes_processed + 3 value := (int)(get_i16(data[1:])) + total_bytes_processed + 3
operand = (DirectWithinSegment)(value) operand = Immediate { value = u16(value), size = .Signed16 }
processed^ += 2 processed^ += 2
case .Intersegment: case .Intersegment:
operand = Intersegment { operand = Intersegment {
@ -133,7 +123,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 = segment_registers[reg] has_segment = registers[SEGMENT_REGISTER_START+reg]
idx += 1 idx += 1
continue continue
} else if inst.opname == .AAM { } else if inst.opname == .AAM {
@ -152,7 +142,6 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
word: bool word: bool
flip: bool flip: bool
indirect_intersegment: bool
op: Operand op: Operand
if inst.has_flip { if inst.has_flip {

View File

@ -11,20 +11,17 @@ execute_instruction :: proc(inst: Instruction) {
if reg_id,ok := inst.dst.(RegisterId); ok { if reg_id,ok := inst.dst.(RegisterId); ok {
// val := registers[reg_id.id].value.full // val := registers[reg_id.id].value.full
#partial switch val in inst.src { #partial switch val in inst.src {
case Immediate8: case Immediate:
if reg_id.access == .Low { if val.size == .Signed16 {
registers[reg_id.id].value.low = (u8)(val) registers[reg_id.id].value.full = (u16)(val.value)
} else { } else {
registers[reg_id.id].value.high = (u8)(val) value := u8(val.value & 0xFF)
}
case ImmediateU8:
if reg_id.access == .Low { if reg_id.access == .Low {
registers[reg_id.id].value.low = (u8)(val) registers[reg_id.id].value.low = value
} else { } else {
registers[reg_id.id].value.high = (u8)(val) registers[reg_id.id].value.high = value
}
} }
case Immediate16:
registers[reg_id.id].value.full = (u16)(val)
case RegisterId: case RegisterId:
switch val.access { switch val.access {
case .Low, .High: case .Low, .High:
@ -37,23 +34,7 @@ execute_instruction :: proc(inst: Instruction) {
case .Full: case .Full:
registers[reg_id.id].value.full = registers[val.id].value.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

@ -141,8 +141,15 @@ get_operand_string :: proc(operand: Operand, has_segment: Maybe(Register)) -> st
string_val = "" string_val = ""
case RegisterId: case RegisterId:
string_val = get_register_name(val) string_val = get_register_name(val)
case Immediate8, ImmediateU8, Immediate16, DirectWithinSegment: case Immediate:
string_val = fmt.aprintf("%d", val) 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))
}
case MemoryAddr: case MemoryAddr:
string_val = get_memory_string(val, has_segment) string_val = get_memory_string(val, has_segment)
case DirectAddress: case DirectAddress:
@ -151,14 +158,8 @@ get_operand_string :: proc(operand: Operand, has_segment: Maybe(Register)) -> st
seg_string = fmt.aprintf("%s:", segreg.fullname) seg_string = fmt.aprintf("%s:", segreg.fullname)
} }
string_val = fmt.aprintf("%s[%d]", seg_string, val) string_val = fmt.aprintf("%s[%d]", seg_string, val)
case SegmentRegister:
string_val = segment_registers[val].fullname
case Jump: case Jump:
string_val = fmt.aprintf("$%s%d", val >= 0 ? "+" : "", val) string_val = fmt.aprintf("$%s%d", val >= 0 ? "+" : "", val)
case VariablePort:
string_val = variable_port.fullname
case ShiftRotate:
string_val = val ? "cl" : "1"
case Repeat: case Repeat:
string_val = (string)(val) string_val = (string)(val)
case Intersegment: case Intersegment:
@ -176,10 +177,10 @@ get_unknown_inst_string :: proc(inst: Instruction) -> string {
get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruction) { get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruction) {
inst := instruction inst := instruction
src_is_imm := operand_is(Immediate8, inst.src) || operand_is(Immediate16, inst.src) src_is_imm := operand_is(Immediate, inst.src)
dst_is_bracketed := operand_is(MemoryAddr, inst.dst) || operand_is(DirectAddress, inst.dst) dst_is_bracketed := operand_is(MemoryAddr, inst.dst) || operand_is(DirectAddress, inst.dst)
src_is_bracketed := operand_is(MemoryAddr, inst.src) || operand_is(DirectAddress, inst.src) src_is_bracketed := operand_is(MemoryAddr, inst.src) || operand_is(DirectAddress, inst.src)
shiftrot := operand_is(ShiftRotate, inst.src) shiftrot := inst_info.opname == .TBD6
size_string := "" size_string := ""
if ((src_is_imm && dst_is_bracketed) || (dst_is_bracketed && shiftrot)) || (src_is_bracketed && operand_is(None, inst.dst)) { if ((src_is_imm && dst_is_bracketed) || (dst_is_bracketed && shiftrot)) || (src_is_bracketed && operand_is(None, inst.dst)) {
size_string = inst.is_word ? "word " : "byte " size_string = inst.is_word ? "word " : "byte "

View File

@ -12,7 +12,7 @@ RIGHT_ALIGN_AMOUNT := 35
// We have to change how we coded this out. Likely we have to remove bytename as an option // 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 // 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 // if it's the high or low part, not sure how to go about that
registers := [8]Register { registers := [?]Register {
{fullname = "ax", code = 0b000}, {fullname = "ax", code = 0b000},
{fullname = "cx", code = 0b001}, {fullname = "cx", code = 0b001},
{fullname = "dx", code = 0b010}, {fullname = "dx", code = 0b010},
@ -21,9 +21,6 @@ registers := [8]Register {
{fullname = "bp", code = 0b101}, {fullname = "bp", code = 0b101},
{fullname = "si", code = 0b110}, {fullname = "si", code = 0b110},
{fullname = "di", code = 0b111}, {fullname = "di", code = 0b111},
}
segment_registers := [4]Register {
{fullname = "es", code = 0b000}, {fullname = "es", code = 0b000},
{fullname = "cs", code = 0b001}, {fullname = "cs", code = 0b001},
{fullname = "ss", code = 0b010}, {fullname = "ss", code = 0b010},
@ -32,6 +29,8 @@ segment_registers := [4]Register {
variable_port := registers[2] variable_port := registers[2]
SEGMENT_REGISTER_START :: 8
// TODO: I don't like this here
total_bytes_processed := 0 total_bytes_processed := 0
get_i16 :: proc(data: []u8) -> i16 { get_i16 :: proc(data: []u8) -> i16 {
@ -108,9 +107,6 @@ main :: proc() {
for reg in registers { for reg in registers {
print_reg(reg) print_reg(reg)
} }
for reg in segment_registers {
print_reg(reg)
}
} }
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[:])

View File

@ -13,7 +13,7 @@ fi
for ASM_BIN in asm_files/*.bin; for ASM_BIN in asm_files/*.bin;
do do
./sim8086 "$ASM_BIN" > output.asm 2> /dev/null ./sim8086 "$ASM_BIN" instructions > output.asm 2> /dev/null
nasm output.asm -o output.bin 2> /dev/null nasm output.asm -o output.bin 2> /dev/null
ASM_FILE=${ASM_BIN%.*}.asm ASM_FILE=${ASM_BIN%.*}.asm
if [ ! -e output.bin ]; then if [ ! -e output.bin ]; then

View File

@ -39,39 +39,35 @@ RegisterId :: struct {
access: RegisterAccess, access: RegisterAccess,
id: int, id: int,
} }
Immediate8 :: distinct i8 ImmediateSize :: enum {
Immediate16 :: distinct i16 Signed8,
ImmediateU8 :: distinct u8 Unsigned8,
Signed16,
}
Immediate :: struct {
value: u16,
size: ImmediateSize,
}
MemoryAddr :: struct { MemoryAddr :: struct {
addr_id: u8, addr_id: u8,
displacement: Displacement, displacement: Displacement,
} }
DirectAddress :: distinct i16 DirectAddress :: distinct i16
SegmentRegister :: distinct i16
Jump :: distinct i8 Jump :: distinct i8
VariablePort :: struct {}
ShiftRotate :: distinct bool
Repeat :: string Repeat :: string
Intersegment :: struct { Intersegment :: struct {
ip: i16, ip: i16,
cs: i16, cs: i16,
} }
DirectWithinSegment :: distinct u16
Operand :: union { Operand :: union {
None, None,
RegisterId, RegisterId,
Immediate8, Immediate,
ImmediateU8,
Immediate16,
MemoryAddr, MemoryAddr,
DirectAddress, DirectAddress,
SegmentRegister,
Jump, Jump,
VariablePort,
ShiftRotate,
Repeat, Repeat,
DirectWithinSegment,
Intersegment, Intersegment,
} }
@ -122,7 +118,9 @@ Instruction :: struct {
dst: Operand, dst: Operand,
info: InstructionInfo, info: InstructionInfo,
is_word: bool, is_word: bool,
indirect_intersegment: bool, // indirect_intersegment: bool,
// TODO: This is trickier than I thought, it's more than just the one instruction
// that uses it
has_segment: Maybe(Register), has_segment: Maybe(Register),
has_lock: bool, has_lock: bool,
bytes_read: int, bytes_read: int,