Decode then check reference flags, change registers and flags to use enumerated arrays

This commit is contained in:
Joseph Ferano 2025-03-20 16:13:37 +07:00
parent cd5eada115
commit 5cf4768b80
6 changed files with 72 additions and 40 deletions

View File

@ -80,11 +80,11 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
case .SecondByteLast3: reg = data[1] & 0b111 case .SecondByteLast3: reg = data[1] & 0b111
} }
if opinfo == .SegmentRegister { if opinfo == .SegmentRegister {
operand = (RegisterId){idx = SEGMENT_REGISTER_START + (int)(reg), access = .Full} operand = (RegisterId){name = Register(SEGMENT_REGISTER_START + (int)(reg)), access = .Full}
} else if word { } else if word {
operand = RegisterId { idx = (int)(reg), access = .Full } operand = RegisterId { name = Register(reg), access = .Full }
} else { } else {
operand = RegisterId { idx = (int)(reg % 4), access = reg < 4 ? .Low : .High } operand = RegisterId { name = Register(reg % 4), access = reg < 4 ? .Low : .High }
} }
case .RegisterMemory: case .RegisterMemory:
mod := data[1] >> 6 mod := data[1] >> 6
@ -107,9 +107,9 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
processed^ += 2 processed^ += 2
} else if mod == 3 { } else if mod == 3 {
if word { if word {
op = RegisterId { idx = (int)(rm), access = .Full } op = RegisterId { name = Register(rm), access = .Full }
} else { } else {
op = RegisterId { idx = (int)(rm % 4), access = rm < 4 ? .Low : .High } op = RegisterId { name = Register(rm % 4), access = rm < 4 ? .Low : .High }
} }
} }
operand = op operand = op
@ -126,7 +126,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
operand = Immediate { value = u16(data[processed^]), size = .Unsigned8 } operand = Immediate { value = u16(data[processed^]), size = .Unsigned8 }
processed^ += 1 processed^ += 1
case .Accumulator: case .Accumulator:
operand = RegisterId { idx = 0, access = word ? .Full : .Low } operand = RegisterId { name = Register(0), access = word ? .Full : .Low }
case .DirectAddress: case .DirectAddress:
// operand = DirectAddress { value = get_i16(data[1:]) } // operand = DirectAddress { value = get_i16(data[1:]) }
operand = (DirectAddress)(get_i16(data[1:])) operand = (DirectAddress)(get_i16(data[1:]))
@ -136,10 +136,10 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
// NOTE: In order to mimic the label offset, you have to take the value you got and add two // NOTE: In order to mimic the label offset, you have to take the value you got and add two
operand = (Jump)((i8)(data[1]) + 2) operand = (Jump)((i8)(data[1]) + 2)
case .VariablePort: case .VariablePort:
operand = RegisterId { idx = (int)(Register.dx), access = .Full } operand = RegisterId { name = Register.dx, access = .Full }
case .ShiftRotate: case .ShiftRotate:
v_flag := data[0] & 0b10 != 0 v_flag := data[0] & 0b10 != 0
operand = v_flag ? RegisterId { idx = 1, access = .Low } : Immediate { value = 1 } operand = v_flag ? RegisterId { name = Register(1), access = .Low } : Immediate { value = 1 }
case .Repeat: case .Repeat:
bits := (data[1] & 0b1110) >> 1 bits := (data[1] & 0b1110) >> 1
w := (data[1] & 0b1) == 1 ? "w" : "b" w := (data[1] & 0b1) == 1 ? "w" : "b"
@ -203,7 +203,7 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
continue continue
} else if inst.opname == .SEGMENT { } else if inst.opname == .SEGMENT {
reg := (curr_byte & 0b11000) >> 3 reg := (curr_byte & 0b11000) >> 3
has_segment = RegisterId { idx = int(SEGMENT_REGISTER_START+reg) } has_segment = RegisterId { name = Register(SEGMENT_REGISTER_START+reg) }
idx += 1 idx += 1
continue continue
} else if inst.opname == .AAM { } else if inst.opname == .AAM {

View File

@ -11,7 +11,7 @@ get_operand_value :: proc(operand: Operand) -> u16 {
case Immediate: case Immediate:
return opr.value return opr.value
case RegisterId: case RegisterId:
reg_val := CPU.registers[opr.idx] reg_val := CPU.registers[opr.name]
switch opr.access { switch opr.access {
case .Low, .High: case .Low, .High:
return u16(opr.access == .Low ? reg_val.low : reg_val.high) return u16(opr.access == .Low ? reg_val.low : reg_val.high)
@ -25,25 +25,25 @@ get_operand_value :: proc(operand: Operand) -> u16 {
set_register_value :: proc(reg: RegisterId, value: u16) { set_register_value :: proc(reg: RegisterId, value: u16) {
switch reg.access { switch reg.access {
case .Low: case .Low:
CPU.registers[reg.idx].low = u8(value) CPU.registers[reg.name].low = u8(value)
case .High: case .High:
CPU.registers[reg.idx].high = u8(value) CPU.registers[reg.name].high = u8(value)
case .Full: case .Full:
CPU.registers[reg.idx].full = u16(value) CPU.registers[reg.name].full = u16(value)
} }
} }
get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue { get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue {
reg,_ := reflect.enum_from_name(Register, name) reg,_ := reflect.enum_from_name(Register, name)
return &cpu.registers[int(reg)] return &cpu.registers[reg]
} }
check_zero_flag :: proc(value: u16) { check_zero_flag :: proc(value: u16) {
CPU.flags.ZF = value == 0 CPU.flags[.ZF] = value == 0
} }
check_sign_flag :: proc(value: u16) { check_sign_flag :: proc(value: u16) {
CPU.flags.SF = value >> 15 == 1 CPU.flags[.SF] = value >> 15 == 1
} }
execute_instruction :: proc(inst: Instruction) { execute_instruction :: proc(inst: Instruction) {
@ -54,19 +54,19 @@ execute_instruction :: proc(inst: Instruction) {
set_register_value(reg, src_val) set_register_value(reg, src_val)
case .ADD: case .ADD:
src_val := get_operand_value(inst.src) src_val := get_operand_value(inst.src)
val := CPU.registers[reg.idx].full + src_val val := CPU.registers[reg.name].full + src_val
set_register_value(reg, val) set_register_value(reg, val)
check_zero_flag(val) check_zero_flag(val)
check_sign_flag(val) check_sign_flag(val)
case .SUB: case .SUB:
src_val := get_operand_value(inst.src) src_val := get_operand_value(inst.src)
val := CPU.registers[reg.idx].full - src_val val := CPU.registers[reg.name].full - src_val
set_register_value(reg, val) set_register_value(reg, val)
check_zero_flag(val) check_zero_flag(val)
check_sign_flag(val) check_sign_flag(val)
case .CMP: case .CMP:
src_val := get_operand_value(inst.src) src_val := get_operand_value(inst.src)
val := CPU.registers[reg.idx].full - src_val val := CPU.registers[reg.name].full - src_val
check_zero_flag(val) check_zero_flag(val)
check_sign_flag(val) check_sign_flag(val)
} }

View File

@ -78,9 +78,9 @@ get_register_name :: proc(reg_id: RegisterId) -> string {
low_names := [?]string{"al", "cl", "dl", "bl"} low_names := [?]string{"al", "cl", "dl", "bl"}
high_names := [?]string{"ah", "ch", "dh", "bh"} high_names := [?]string{"ah", "ch", "dh", "bh"}
switch reg_id.access { switch reg_id.access {
case .Full: return reflect.enum_string(Register(reg_id.idx)) case .Full: return reflect.enum_string(reg_id.name)
case .Low: return low_names[reg_id.idx] case .Low: return low_names[int(reg_id.name)]
case .High: return high_names[reg_id.idx % 4] case .High: return high_names[int(reg_id.name) % 4]
} }
return "" return ""
} }

View File

@ -5,6 +5,7 @@ import path "core:path/filepath"
import "core:fmt" import "core:fmt"
import "core:math" import "core:math"
import "core:strings" import "core:strings"
import "core:reflect"
CPU := Cpu { CPU := Cpu {
memory = make([dynamic]u8, 65536), memory = make([dynamic]u8, 65536),
@ -42,21 +43,31 @@ main :: proc() {
} }
if what_to_print == "registers" || what_to_print == "all" { if what_to_print == "registers" || what_to_print == "all" {
for reg,i in CPU.registers { fmt.println("\nRegisters")
full := fmt.aprintf("%s: %d ", get_register_name(RegisterId{idx=i}), reg.full) for reg_val,name in CPU.registers {
hex := fmt.aprintf("0x%04x ", reg.full) full := fmt.aprintf("%s: %d ", name, reg_val.full)
hex := fmt.aprintf("0x%04x ", reg_val.full)
fmt.printf("%s %*[1]s %s %*[4]s %08b %08b", fmt.printf("%s %*[1]s %s %*[4]s %08b %08b",
full, 18 - len(full), "|", hex, 10 - len(hex), "|", reg.high, reg.low) full, 18 - len(full), "|", hex, 10 - len(hex), "|", reg_val.high, reg_val.low)
fmt.println() fmt.println()
} }
fmt.println("\nFlags")
for state,flag in CPU.flags {
fmt.printfln("%c: %d",reflect.enum_string(flag)[0], state ? 1 : 0)
}
path,ok := strings.replace(os.args[1], ".bin", ".txt", 1) path,ok := strings.replace(os.args[1], ".bin", ".txt", 1)
expected_cpu,_ := extract_expected_cpu_state(path) ref_cpu,_ := extract_reference_cpu_state(path)
for reg,i in expected_cpu.registers { for reg_val,name in ref_cpu.registers {
if CPU.registers[i].full != reg.full { if CPU.registers[name].full != reg_val.full {
name := get_register_name(RegisterId{idx=i}) msg := "%s register does not match reference - Expected %04x | Actual %04x"
msg := "%s register does not match - Expected %04x | Actual %04x" fmt.eprintfln(msg, name, reg_val.full, CPU.registers[name].full)
fmt.eprintfln(msg, name, reg.full, CPU.registers[i].full) }
}
for f in Flag {
if ref_cpu.flags[f] != CPU.flags[f] {
msg := "%s flag does not match reference - Expected %t | Actual %t"
fmt.eprintfln(msg, f, ref_cpu.flags[f], CPU.flags[f])
} }
} }
} }

View File

@ -5,8 +5,9 @@ import "core:fmt"
import "core:math" import "core:math"
import "core:strings" import "core:strings"
import "core:strconv" import "core:strconv"
import "core:reflect"
extract_expected_cpu_state :: proc(filename: string) -> (Cpu, bool) { extract_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) {
cpu: Cpu cpu: Cpu
data,ok := os.read_entire_file(filename) data,ok := os.read_entire_file(filename)
@ -27,7 +28,18 @@ extract_expected_cpu_state :: proc(filename: string) -> (Cpu, bool) {
} else if c == ' ' { } else if c == ' ' {
space_count += 1 space_count += 1
} else { } else {
if line[i:i+5] != "flags" { if line[i:i+5] == "flags" {
idx := i + 7
for idx < len(line) {
flag_name := fmt.tprintf("%cF", line[idx])
if flag,ok := reflect.enum_from_name(Flag, flag_name); ok {
cpu.flags[flag] = true
} else {
fmt.eprintfln("Error parsing flag enum %s", flag_name)
}
idx += 1
}
} else {
reg_name := line[i:i+2] reg_name := line[i:i+2]
reg_value := get_cpu_register_by_name(&cpu, reg_name) reg_value := get_cpu_register_by_name(&cpu, reg_name)
hex_string := line[i+6:i+10] hex_string := line[i+6:i+10]

View File

@ -22,9 +22,18 @@ RegisterValue :: struct #raw_union {
full: u16, full: u16,
} }
Flags :: struct { Flag :: enum {
ZF: bool, OF,
SF: bool, SF,
ZF,
AF,
PF,
CF,
// NOTE: These are the control flags, previous are status flags, justing noting in
// case we have to make that distinction in later modeling
TF,
DF,
IF,
} }
WordSize :: enum { WordSize :: enum {
@ -51,7 +60,7 @@ RegisterAccess :: enum {
} }
RegisterId :: struct { RegisterId :: struct {
idx: int, name: Register,
access: RegisterAccess, access: RegisterAccess,
} }
ImmediateSize :: enum { ImmediateSize :: enum {
@ -144,8 +153,8 @@ Instruction :: struct {
} }
Cpu :: struct { Cpu :: struct {
flags: Flags, flags: [Flag]bool,
registers: [12]RegisterValue, registers: [Register]RegisterValue,
memory: [dynamic]u8, memory: [dynamic]u8,
total_bytes_processed: int total_bytes_processed: int
} }