performance-aware/decoder8086.odin

189 lines
5.7 KiB
Odin

package decoder_8086
import "core:os"
import "core:fmt"
Register :: struct {
fullname: string,
bytename: string,
value: struct #raw_union {
using _: struct {
low, high: byte,
},
full: u16,
},
code: u8,
}
RegMemMode :: enum {
Memory00 = 0b00,
Memory08 = 0b01,
Memory16 = 0b10,
Register = 0b11,
};
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},
}
Instruction :: struct {
mask: u8,
encoding: u8,
name: string,
desc: string,
}
instructions := [?]Instruction {
{ mask = 0b11111100, encoding = 0b10001000, name = "mov", desc = "Register/memory to/from register" },
{ mask = 0b11111110, encoding = 0b11000110, name = "mov", desc = "Immediate to register/memory" },
{ mask = 0b11110000, encoding = 0b10110000, name = "mov", desc = "Immediate to register" },
{ mask = 0b11111110, encoding = 0b10100000, name = "mov", desc = "Memory to accumulator" },
{ mask = 0b11111110, encoding = 0b10100010, name = "mov", desc = "Accumulator to memory" },
{ mask = 0b11111111, encoding = 0b10001110, name = "mov", desc = "Register/memory to segment register" },
{ mask = 0b11111111, encoding = 0b10001100, name = "mov", desc = "Segment register to register/memory" },
}
inst_map := make(map[u8]Instruction)
RIGHT_ALIGN_AMOUNT := 30
get_instruction :: proc(bytes: []u8) -> (Instruction, u8) {
return {}, 0
}
calculate_effective_address :: proc(r_m: u8) -> string {
val: string
switch r_m {
case 0b000:
val = "bx + si"
case 0b001:
val = "bx + di"
case 0b010:
val = "bp + si"
case 0b011:
val = "bp + di"
case 0b100:
val = "si"
case 0b101:
val = "di"
case 0b110:
val = "bp"
case 0b111:
val = "bx"
}
return val
}
main :: proc() {
ax := registers[0]
ax.value.full = 52428
f,err := os.open(len(os.args) > 1 ? os.args[1] : "./asm_files/01-02-39.bin")
if err != os.ERROR_NONE {
os.exit(1)
}
defer os.close(f)
data := make([]u8, 512)
bytes_read, err2 := os.read(f, data)
if err2 != nil {
// ...
os.exit(1)
}
for inst in instructions {
inst_map[inst.encoding] = inst
}
if false {
for i in 0..<bytes_read {
fmt.printfln("Checking %b:", data[i])
mask: u8 = 0xFF
for j in 0..=4 {
encoding := data[i] & mask
fmt.printfln("\tNext: %b %b", data[i], encoding)
if inst, ok := inst_map[encoding]; ok {
fmt.printfln("\t%b, %v", encoding, inst.desc)
break
}
mask <<= 1
}
}
os.exit(0)
}
read_next := false
src_dst := true
fmt.println("bits 16\n")
processed := 0
for processed < bytes_read {
curr_byte := data[processed]
if curr_byte & 0b11111000 == 0b10001000 {
is_word := curr_byte & 1 == 1
flip_src := curr_byte & 2 != 0
disp_amount := 0
next_byte := data[processed + 1]
mod := (next_byte & 0b11000000) >> 6
reg := (next_byte & 0b00111000) >> 3
rm := next_byte & 0b00000111
dst_reg := registers[rm]
disp: string
if mod == 1 {
disp_byte := (i16)(data[processed + 2])
disp_amount = 1
disp = disp_byte == 0 ? "" : fmt.aprintf(" + %d", disp_byte)
} else if mod == 2 {
disp_byte := (i16)(data[processed + 3]) << 8 | (i16)(data[processed + 2])
disp_amount = 2
disp = disp_byte == 0 ? "" : fmt.aprintf(" + %d", disp_byte)
} else {
disp = ""
}
src_name: string
if mod == 3 {
// Register-to-register
src_name = is_word ? registers[rm].fullname : registers[rm].bytename
} else {
src_name = fmt.aprintf("[%s%s]", calculate_effective_address(rm), disp)
}
dst_name := is_word ? registers[reg].fullname : registers[reg].bytename
if flip_src { src_name, dst_name = dst_name, src_name }
processed += 1 + ((int)(mod) % 3)
inst_string := fmt.aprintf("mov %s, %s", src_name, dst_name)
fmt.printfln("%s %*[1]s %08b %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";; 1", curr_byte, next_byte)
} else if curr_byte & 0b1111_0000 == 0b10110000 {
is_word := curr_byte & 0b0000_1000 != 0
reg := curr_byte & 0b00000111
dst_name: string
imm: i16
if is_word {
dst_name = registers[reg].fullname
imm = (i16)(data[processed+2]) << 8 | (i16)(data[processed+1])
processed += 2
} else {
dst_name = registers[reg].bytename
imm = (i16)(data[processed+1])
processed += 1
}
inst_string := fmt.aprintf("mov %s, %d", dst_name, imm)
fmt.printfln("%s %*[1]s %08b %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";; 2", curr_byte, data[processed + 1])
} else {
fmt.printfln("unknown instruction ;; %b", curr_byte)
}
processed += 1
}
}