performance-aware/sim8086.odin

120 lines
3.3 KiB
Odin

package sim_8086
import "core:os"
import "core:fmt"
import "core:math"
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 {
{fullname = "ax", code = 0b000},
{fullname = "cx", code = 0b001},
{fullname = "dx", code = 0b010},
{fullname = "bx", code = 0b011},
{fullname = "sp", code = 0b100},
{fullname = "bp", code = 0b101},
{fullname = "si", code = 0b110},
{fullname = "di", code = 0b111},
{fullname = "es", code = 0b000},
{fullname = "cs", code = 0b001},
{fullname = "ss", code = 0b010},
{fullname = "ds", code = 0b011},
}
variable_port := registers[2]
SEGMENT_REGISTER_START :: 8
CPU := Cpu {
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() {
f,err := os.open(os.args[1])
if err != os.ERROR_NONE {
fmt.eprintln("ERROR:", err)
os.exit(1)
}
defer os.close(f)
what_to_print := len(os.args) >= 3 ? os.args[2] : ""
data := make([]u8, 1024)
bytes_read, err2 := os.read(f, data)
if err2 != nil {
// ...
os.exit(1)
}
// asdf :u16 = 0b00000110_11011101
// asdf2 :i16 = (i16)(asdf)
// fmt.printfln("%d", asdf2)
print_at_end := false
line_count := 0
instruction_list := make([dynamic]string, 0, 512)
instructions_list := make([dynamic]Instruction, 0, 512)
decode_data(&instructions_list, data[:], bytes_read)
for inst in instructions_list {
execute_instruction(inst)
}
if what_to_print == "registers" || what_to_print == "all" {
print_reg :: proc(reg: Register) {
full := fmt.aprintf("%s: %d ", reg.fullname, reg.value.full)
hex := fmt.aprintf("0x%04x ", reg.value.full)
fmt.printf("%s %*[1]s %s %*[4]s %08b %08b",
full, 18 - len(full), "|", hex, 10 - len(hex), "|", reg.value.high, reg.value.low)
fmt.println()
}
for reg in registers {
print_reg(reg)
}
}
if what_to_print == "instructions" || what_to_print == "all" {
print_instructions_stdout(instructions_list[:])
}
}