400 lines
12 KiB
Odin
400 lines
12 KiB
Odin
package decoder_8086
|
|
|
|
import "core:os"
|
|
import "core:fmt"
|
|
import "core:math"
|
|
|
|
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,
|
|
};
|
|
|
|
OpCode :: enum {
|
|
MOV,
|
|
ADD,
|
|
SUB,
|
|
CMP,
|
|
JMP,
|
|
}
|
|
|
|
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" },
|
|
}
|
|
|
|
ParsedInstruction :: struct {
|
|
code: OpCode,
|
|
displacement: DisplacementMode,
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
ModMemory :: struct {}
|
|
Mod8BitDisp :: i8
|
|
Mod16BitDisp :: i16
|
|
ModRegister :: struct {}
|
|
|
|
DisplacementMode :: union {
|
|
ModMemory,
|
|
Mod8BitDisp,
|
|
Mod16BitDisp,
|
|
ModRegister,
|
|
}
|
|
|
|
ModField :: struct {
|
|
displacement: DisplacementMode
|
|
}
|
|
|
|
None :: struct {}
|
|
Disp8 :: i8
|
|
Disp16 :: i16
|
|
Displacement :: union {
|
|
None,
|
|
Disp8,
|
|
Disp16
|
|
}
|
|
|
|
RegisterId :: u8
|
|
Immediate8 :: i8
|
|
Immediate16 :: i16
|
|
MemoryAddr :: struct {
|
|
addr_id: u8,
|
|
displacement: Displacement
|
|
}
|
|
|
|
get_memory_string :: proc(memoryAddr: MemoryAddr) -> string {
|
|
disp: string
|
|
switch value in memoryAddr.displacement {
|
|
case None:
|
|
disp = ""
|
|
case Disp8:
|
|
if value != 0 {
|
|
disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value))
|
|
}
|
|
case Disp16:
|
|
if value != 0 {
|
|
disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value))
|
|
}
|
|
}
|
|
text := fmt.aprintf("[%s%s]", calculate_effective_address(memoryAddr.addr_id), disp)
|
|
return text
|
|
}
|
|
|
|
MemoryType :: union {
|
|
RegisterId,
|
|
MemoryAddr
|
|
}
|
|
|
|
OperandType :: union {
|
|
RegisterId,
|
|
Immediate8,
|
|
Immediate16,
|
|
MemoryAddr
|
|
}
|
|
|
|
get_i16 :: proc(data: []u8) -> i16 {
|
|
return (i16)(data[1]) << 8 | (i16)(data[0])
|
|
}
|
|
|
|
parse_displacement :: proc(data: []u8) -> (displacement: DisplacementMode, disp_amount: int) {
|
|
mod := (data[0] & 0b11000000) >> 6
|
|
disp: DisplacementMode
|
|
amount: int
|
|
switch mod {
|
|
case 0:
|
|
disp = ModMemory{}
|
|
case 1:
|
|
disp = (i8)(data[1])
|
|
amount = 1
|
|
case 2:
|
|
disp = get_i16(data[1:])
|
|
amount = 2
|
|
case 3:
|
|
disp = ModRegister{}
|
|
}
|
|
return disp, amount
|
|
}
|
|
|
|
get_displacement_string :: proc(displacement: DisplacementMode) -> string {
|
|
disp := ""
|
|
#partial switch value in displacement {
|
|
case i8:
|
|
if value != 0 {
|
|
disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value))
|
|
}
|
|
case i16:
|
|
if value != 0 {
|
|
disp = fmt.aprintf(" %s %d", value > 0 ? "+" : "-", math.abs(value))
|
|
}
|
|
}
|
|
return disp
|
|
}
|
|
|
|
try_find_instruction :: proc(b: u8) -> (Instruction, bool) {
|
|
mask: u8 = 0xFF
|
|
for j in 0..=4 {
|
|
encoding := b & mask
|
|
if inst, ok := inst_map[encoding]; ok {
|
|
return inst, true
|
|
}
|
|
mask <<= 1
|
|
}
|
|
return Instruction{}, false
|
|
}
|
|
|
|
main :: proc() {
|
|
f,err := os.open(len(os.args) > 1 ? os.args[1] : "./asm_files/01-02-39.bin")
|
|
// f,err := os.open(len(os.args) > 1 ? os.args[1] : "./asm_files/01-02-40.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 {
|
|
os.exit(0)
|
|
}
|
|
|
|
read_next := false
|
|
src_dst := true
|
|
fmt.println("bits 16\n")
|
|
idx := 0
|
|
for idx < bytes_read {
|
|
processed := 0
|
|
curr_byte := data[idx]
|
|
|
|
|
|
inst_name: string
|
|
if instruction, ok := try_find_instruction(curr_byte); ok {
|
|
inst_name = instruction.name
|
|
} else {
|
|
txt := "unknown instruction"
|
|
fmt.printfln("%s %*[1]s %8b", txt, RIGHT_ALIGN_AMOUNT - len(txt), ";;", curr_byte)
|
|
idx += 1
|
|
continue
|
|
}
|
|
|
|
lhs2: OperandType
|
|
rhs2: OperandType
|
|
lhs: string
|
|
rhs: string
|
|
is_word: bool
|
|
is_immediate := false
|
|
flip_dst := false
|
|
|
|
if curr_byte & 0b11110000 == 0b10110000 {
|
|
is_word = curr_byte & 0b0000_1000 != 0
|
|
reg := registers[curr_byte & 0b00000111]
|
|
lhs = is_word ? reg.fullname : reg.bytename
|
|
processed += is_word ? 1 : 0
|
|
lhs2 := (RegisterId)(reg.code)
|
|
rhs2 := (OperandType)(is_word ? ((Immediate16)(get_i16(data[idx+1:]))) : ((Immediate8)(data[idx+1])))
|
|
} else if curr_byte & 0b11111000 == 0b10001000 {
|
|
mod_reg_rm := data[idx + 1]
|
|
is_word = curr_byte & 1 == 1
|
|
flip_dst = curr_byte & 2 != 0
|
|
reg := (mod_reg_rm & 0b00111000) >> 3
|
|
rm := mod_reg_rm & 0b00000111
|
|
mod, disp_amount := parse_displacement(data[idx + 1:])
|
|
switch disp_val in mod {
|
|
case ModMemory:
|
|
lhs2 = (RegisterId)(reg)
|
|
rhs2 = MemoryAddr{ addr_id = rm , displacement = None{} }
|
|
processed += 1
|
|
case Mod8BitDisp:
|
|
lhs2 = (RegisterId)(reg)
|
|
rhs2 = MemoryAddr{ addr_id = rm , displacement = disp_val }
|
|
processed += 1
|
|
case Mod16BitDisp:
|
|
lhs2 = (RegisterId)(reg)
|
|
rhs2 = MemoryAddr{ addr_id = rm , displacement = disp_val }
|
|
processed += 2
|
|
case ModRegister:
|
|
lhs2 = (RegisterId)(rm)
|
|
rhs2 = (RegisterId)(reg)
|
|
processed += 1
|
|
}
|
|
dst_reg := registers[rm]
|
|
}
|
|
|
|
if flip_dst {
|
|
lhs2, rhs2 = rhs2, lhs2
|
|
}
|
|
switch val in lhs2 {
|
|
case RegisterId:
|
|
lhs = fmt.aprintf("%s", is_word ? registers[val].fullname : registers[val].bytename)
|
|
case Immediate8:
|
|
lhs = fmt.aprintf("%d", val)
|
|
case Immediate16:
|
|
lhs = fmt.aprintf("%d", val)
|
|
case MemoryAddr:
|
|
lhs = get_memory_string(val)
|
|
}
|
|
switch val in rhs2 {
|
|
case RegisterId:
|
|
rhs = is_word ? registers[val].fullname : registers[val].bytename
|
|
case Immediate8:
|
|
rhs = fmt.aprintf("%d", val)
|
|
case Immediate16:
|
|
rhs = fmt.aprintf("%d", val)
|
|
case MemoryAddr:
|
|
rhs = get_memory_string(val)
|
|
}
|
|
full_inst := fmt.aprintf("%s %s, %s", inst_name, lhs, rhs)
|
|
processed += 1
|
|
fmt.printf("%s %*[1]s a %08b", full_inst, RIGHT_ALIGN_AMOUNT - len(full_inst), ";;", curr_byte)
|
|
for i in 0..=processed {
|
|
fmt.printf(" %08b", data[processed + 1 + i])
|
|
}
|
|
fmt.println()
|
|
idx += processed
|
|
if true {
|
|
continue
|
|
}
|
|
if curr_byte & 0b11111000 == 0b10001000 || curr_byte & 0b11111110 == 0b11000110 {
|
|
is_imm_mode := curr_byte & 0b11111110 == 0b11000110
|
|
is_word := curr_byte & 1 == 1
|
|
flip_src := curr_byte & 2 != 0
|
|
|
|
next_byte := data[processed + 1]
|
|
reg := (next_byte & 0b00111000) >> 3
|
|
rm := next_byte & 0b00000111
|
|
dst_reg := registers[rm]
|
|
|
|
displacement, disp_amount := parse_displacement(data[processed + 1:])
|
|
|
|
src_name, dst_name: string
|
|
// switch disp_val in displacement {
|
|
// case DisplaceMemoryMode:
|
|
// src_name = is_word ? registers[rm].fullname : registers[rm].bytename
|
|
// if is_imm_mode {
|
|
// if is_word {
|
|
// dst_name = fmt.aprintf("word %d", get_i16(data[processed+2:]))
|
|
// } else {
|
|
// dst_name = fmt.aprintf("byte %d", (i8)(data[processed+2]))
|
|
// }
|
|
// }
|
|
// disp_amount += is_word ? 2 : 1
|
|
// case Displace8Bits:
|
|
// case Displace16Bits:
|
|
// case DisplaceRegisterMode:
|
|
// }
|
|
// if disp_val, ok := displacement.(DisplaceRegisterMode); ok {
|
|
// src_name = is_word ? registers[rm].fullname : registers[rm].bytename
|
|
// } else {
|
|
// src_name = fmt.aprintf("[%s%s]", calculate_effective_address(rm), get_displacement_string(displacement))
|
|
// }
|
|
|
|
if flip_src && !is_imm_mode { src_name, dst_name = dst_name, src_name }
|
|
|
|
inst_string := fmt.aprintf("mov %s, %s", src_name, dst_name)
|
|
|
|
fmt.printf("%s %*[1]s a %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";;", curr_byte)
|
|
for i in 0..=disp_amount {
|
|
fmt.printf(" %08b", data[processed + 1 + i])
|
|
}
|
|
fmt.println()
|
|
processed += 1 + disp_amount
|
|
} else if curr_byte & 0b11110000 == 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 b %08b %08b", inst_string, RIGHT_ALIGN_AMOUNT - len(inst_string), ";; 2", curr_byte, data[processed + 1])
|
|
|
|
} else if curr_byte & 0b11111110 == 0b11000110 {
|
|
is_word := curr_byte & 1 != 0
|
|
fmt.printfln("mov [%s], asdf ;; %08b %8b %8b", "", curr_byte, data[processed + 1], data[processed + 2])
|
|
} else {
|
|
txt := "unknown instruction"
|
|
fmt.printfln("%s %*[1]s %8b", txt, RIGHT_ALIGN_AMOUNT - len(txt), ";;", curr_byte)
|
|
}
|
|
processed += 1
|
|
}
|
|
}
|