WIP: Separate parsing from printing, the easy way

This commit is contained in:
Joseph Ferano 2025-02-16 17:10:29 +07:00
parent fbedf7cf67
commit f8f5744cd3

View File

@ -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
}