Clean up/inline functions and clear out TODOs

This commit is contained in:
Joseph Ferano 2025-03-20 08:19:20 +07:00
parent 266f7a7900
commit b511c6a620
4 changed files with 38 additions and 108 deletions

View File

@ -4,6 +4,10 @@ import "core:fmt"
import "core:math" import "core:math"
import "core:strings" import "core:strings"
get_i16 :: proc(data: []u8) -> i16 {
return (i16)(data[1]) << 8 | (i16)(data[0])
}
get_op :: proc(inst: Instruction) -> (Op, bool) { get_op :: proc(inst: Instruction) -> (Op, bool) {
op: Op op: Op
interseg: bool interseg: bool
@ -12,8 +16,6 @@ get_op :: proc(inst: Instruction) -> (Op, bool) {
case 0b000: op = .INC case 0b000: op = .INC
case 0b001: op = .DEC case 0b001: op = .DEC
case 0b010: op = .CALL case 0b010: op = .CALL
// TODO: We really have to fix this because we shouldn't be figuring out if this
// is an intersegment here
case 0b011: op = .CALL; interseg = true case 0b011: op = .CALL; interseg = true
case 0b100: op = .JMP case 0b100: op = .JMP
case 0b101: op = .JMP; interseg = true case 0b101: op = .JMP; interseg = true
@ -137,10 +139,20 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
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 { id = 1, access = .Low } : Immediate { value = 1 }
case .Repeat: case .Repeat:
operand = get_repeat_op(data[1]) bits := (data[1] & 0b1110) >> 1
w := (data[1] & 0b1) == 1 ? "w" : "b"
rep: string
switch bits {
case 0b010: rep = "movs"
case 0b011: rep = "cmps"
case 0b101: rep = "stos"
case 0b110: rep = "lods"
case 0b111: rep = "scas"
}
operand = Repeat(fmt.aprintf("%s%s", rep, w))
processed^ += 1 processed^ += 1
case .DirectWithinSegment: case .DirectWithinSegment:
value := (int)(get_i16(data[1:])) + total_bytes_processed + 3 value := (int)(get_i16(data[1:])) + CPU.total_bytes_processed + 3
operand = Immediate { value = u16(value), size = .Signed16 } operand = Immediate { value = u16(value), size = .Signed16 }
processed^ += 2 processed^ += 2
case .Intersegment: case .Intersegment:
@ -162,8 +174,16 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
processed := 1 processed := 1
curr_byte := data[idx] curr_byte := data[idx]
inst, ok := try_find_instruction(curr_byte) found_inst: bool
if !ok { inst: InstructionInfo
for i in instructions {
if i.encoding == (curr_byte & i.mask) {
found_inst = true
inst = i
break
}
}
if !found_inst {
instruction = { instruction = {
opname = .UNKNOWN, opname = .UNKNOWN,
bytes_read = 1, bytes_read = 1,
@ -240,6 +260,6 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
has_lock = false has_lock = false
has_segment = nil has_segment = nil
total_bytes_processed = idx CPU.total_bytes_processed = idx
} }
} }

View File

@ -3,9 +3,17 @@ package sim_8086
import "core:fmt" import "core:fmt"
import "core:math" import "core:math"
import "core:strings" import "core:strings"
import "core:reflect"
instruction_builder := strings.builder_make() instruction_builder := strings.builder_make()
RIGHT_ALIGN_AMOUNT := 35
operand_is :: proc($T: typeid, opr: Operand) -> bool {
_, ok := opr.(T)
return ok
}
calculate_effective_address :: proc(r_m: u8) -> string { calculate_effective_address :: proc(r_m: u8) -> string {
val: string val: string
switch r_m { switch r_m {
@ -66,63 +74,6 @@ get_displacement_string :: proc(displacement: Displacement) -> string {
return disp return disp
} }
get_opname :: proc(inst: Instruction) -> (string, bool) {
name: string
interseg: bool
if inst.opname == .TBD2 {
switch inst.raw_data[1] & 0b00111000 >> 3 {
case 0b000: name = "inc"
case 0b001: name = "dec"
case 0b010: name = "call"
// TODO: We really have to fix this because we shouldn't be figuring out if this
// is an intersegment here
case 0b011: name = "call"; interseg = true
case 0b100: name = "jmp"
case 0b101: name = "jmp"; interseg = true
case 0b110: name = "push"
}
} else if inst.opname == .TBD5 {
switch inst.raw_data[1] & 0b00111000 >> 3 {
case 0b000: name = "test"
case 0b001: name = "dec"
case 0b010: name = "not"
case 0b011: name = "neg"
case 0b100: name = "mul"
case 0b101: name = "imul"
case 0b110: name = "div"
case 0b111: name = "idiv"
}
} else if inst.opname == .TBD6 {
switch inst.raw_data[1] & 0b00111000 >> 3 {
case 0b000: name = "rol"
case 0b001: name = "ror"
case 0b010: name = "rcl"
case 0b011: name = "rcr"
case 0b100: name = "shl"
case 0b101: name = "shr"
case 0b111: name = "sar"
}
} else {
bits: u8
if inst.opname == .TBD1 || inst.opname == .TBD3 {
bits = inst.raw_data[0] & 0b00111000 >> 3
} else {
bits = inst.raw_data[1] & 0b00111000 >> 3
}
switch bits {
case 0b000: name = "add"
case 0b001: name = "or"
case 0b010: name = "adc"
case 0b011: name = "sbb"
case 0b100: name = "and"
case 0b101: name = "sub"
case 0b110: name = "xor"
case 0b111: name = "cmp"
}
}
return name, interseg
}
get_register_name :: proc(reg_id: RegisterId) -> string { 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"}
@ -194,8 +145,8 @@ get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruct
src_str := get_operand_string(inst.src, inst.has_segment) src_str := get_operand_string(inst.src, inst.has_segment)
opname: string opname: string
is_interseg: bool is_interseg: bool
// TODO: Do the RTTI thing here with reflection
opname = strings.to_lower(fmt.aprintf("%s", inst.opname)) opname = strings.to_lower(reflect.enum_string(inst.opname))
if dst_str == "" { if dst_str == "" {
interseg_string: string interseg_string: string

View File

@ -5,13 +5,6 @@ import "core:fmt"
import "core:math" import "core:math"
import "core:strings" 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 := [?]Register { registers := [?]Register {
{fullname = "ax", code = 0b000}, {fullname = "ax", code = 0b000},
{fullname = "cx", code = 0b001}, {fullname = "cx", code = 0b001},
@ -35,41 +28,6 @@ CPU := Cpu {
memory = make([dynamic]u8, 65536) memory = make([dynamic]u8, 65536)
} }
// TODO: I don't like this here
total_bytes_processed := 0
get_i16 :: proc(data: []u8) -> i16 {
return (i16)(data[1]) << 8 | (i16)(data[0])
}
operand_is :: proc($T: typeid, opr: Operand) -> bool {
_, ok := opr.(T)
return ok
}
get_repeat_op :: proc(data: u8) -> Repeat {
bits := (data & 0b1110) >> 1
w := (data & 0b1) == 1 ? "w" : "b"
rep: string
switch bits {
case 0b010: rep = "movs"
case 0b011: rep = "cmps"
case 0b101: rep = "stos"
case 0b110: rep = "lods"
case 0b111: rep = "scas"
}
return Repeat(fmt.aprintf("%s%s", rep, w))
}
try_find_instruction :: proc(b: u8) -> (InstructionInfo, bool) {
for inst in instructions {
if inst.encoding == (b & inst.mask) {
return inst, true
}
}
return InstructionInfo{}, false
}
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 {

View File

@ -135,4 +135,5 @@ Instruction :: struct {
Cpu :: struct { Cpu :: struct {
flags: Flags, flags: Flags,
memory: [dynamic]u8, memory: [dynamic]u8,
total_bytes_processed: int
} }