WIP: Separate parsing from printing, the easy way
This commit is contained in:
parent
fbedf7cf67
commit
f8f5744cd3
307
decoder8086.odin
307
decoder8086.odin
@ -2,6 +2,7 @@ package decoder_8086
|
||||
|
||||
import "core:os"
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
|
||||
Register :: struct {
|
||||
fullname: string,
|
||||
@ -22,6 +23,14 @@ RegMemMode :: enum {
|
||||
Register = 0b11,
|
||||
};
|
||||
|
||||
OpCode :: enum {
|
||||
MOV,
|
||||
ADD,
|
||||
SUB,
|
||||
CMP,
|
||||
JMP,
|
||||
}
|
||||
|
||||
registers := [8]Register {
|
||||
{fullname = "ax", bytename = "al", code = 0b000},
|
||||
{fullname = "cx", bytename = "cl", code = 0b001},
|
||||
@ -50,6 +59,11 @@ instructions := [?]Instruction {
|
||||
{ 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
|
||||
|
||||
@ -80,10 +94,122 @@ calculate_effective_address :: proc(r_m: u8) -> string {
|
||||
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() {
|
||||
ax := registers[0]
|
||||
ax.value.full = 52428
|
||||
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)
|
||||
}
|
||||
@ -101,69 +227,150 @@ main :: proc() {
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
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)
|
||||
}
|
||||
displacement, disp_amount := parse_displacement(data[processed + 1:])
|
||||
|
||||
dst_name := is_word ? registers[reg].fullname : registers[reg].bytename
|
||||
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 { src_name, dst_name = dst_name, src_name }
|
||||
|
||||
processed += 1 + ((int)(mod) % 3)
|
||||
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.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 {
|
||||
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
|
||||
@ -178,10 +385,14 @@ main :: proc() {
|
||||
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])
|
||||
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 {
|
||||
fmt.printfln("unknown instruction ;; %b", curr_byte)
|
||||
txt := "unknown instruction"
|
||||
fmt.printfln("%s %*[1]s %8b", txt, RIGHT_ALIGN_AMOUNT - len(txt), ";;", curr_byte)
|
||||
}
|
||||
processed += 1
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user