Generalize with perform_load and perform_store, use bit_set for cpu flags
This commit is contained in:
parent
831a307975
commit
df105ea3cf
177
execution.odin
177
execution.odin
@ -23,7 +23,7 @@ get_effective_address_value :: proc(cpu: ^Cpu, id: u8) -> i16 {
|
||||
return -1
|
||||
}
|
||||
|
||||
get_operand_value :: proc(cpu: ^Cpu, operand: Operand) -> i16 {
|
||||
perform_load :: proc(cpu: ^Cpu, operand: Operand, is_word: bool) -> i16 {
|
||||
#partial switch opr in operand {
|
||||
case Immediate:
|
||||
return i16(opr.value)
|
||||
@ -36,51 +36,38 @@ get_operand_value :: proc(cpu: ^Cpu, operand: Operand) -> i16 {
|
||||
return i16(reg_val.full)
|
||||
}
|
||||
case DirectAddress:
|
||||
value := i16(u16(cpu.memory[opr+1] << 8) | u16(cpu.memory[opr]))
|
||||
value: i16
|
||||
if is_word {
|
||||
value = i16(u16(cpu.memory[opr+1] << 8) | u16(cpu.memory[opr]))
|
||||
} else {
|
||||
value = i16(cpu.memory[opr])
|
||||
}
|
||||
return value
|
||||
case MemoryAddr:
|
||||
value: i16
|
||||
idx := get_effective_address_value(cpu, opr.addr_id) + opr.displacement
|
||||
value := i16(u16(cpu.memory[idx+1] << 8) | u16(cpu.memory[idx]))
|
||||
// fmt.println("Checking", idx)
|
||||
// for i in 0..<6 {
|
||||
// fmt.printf("%04x ", cpu.memory[int(idx)-3+i])
|
||||
// }
|
||||
// fmt.println()
|
||||
if is_word {
|
||||
value = i16(u16(cpu.memory[idx+1] << 8) | u16(cpu.memory[idx]))
|
||||
} else {
|
||||
value = i16(cpu.memory[idx])
|
||||
}
|
||||
return value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
set_register_value :: proc(cpu: ^Cpu, reg: RegisterId, value: i16) {
|
||||
switch reg.access {
|
||||
case .Low:
|
||||
cpu.registers[reg.name].low = u8(value)
|
||||
case .High:
|
||||
cpu.registers[reg.name].high = u8(value)
|
||||
case .Full:
|
||||
cpu.registers[reg.name].full = i16(value)
|
||||
}
|
||||
}
|
||||
|
||||
get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue {
|
||||
reg,_ := reflect.enum_from_name(Register, name)
|
||||
return &cpu.registers[reg]
|
||||
}
|
||||
|
||||
check_zero_flag :: proc(cpu: ^Cpu, value: i16) {
|
||||
cpu.flags[.ZF] = value == 0
|
||||
}
|
||||
|
||||
check_sign_flag :: proc(cpu: ^Cpu, value: i16) {
|
||||
cpu.flags[.SF] = (value >> 15) & 0x1 == 1
|
||||
}
|
||||
|
||||
check_carry_flag :: proc(cpu: ^Cpu, dst: i16, src: i16, is_add: bool) {
|
||||
check_flags :: proc(cpu: ^Cpu, flags: bit_set[Flag], dst: i16, src: i16, result: i16, is_add: bool) {
|
||||
if .ZF in flags do cpu.flags[.ZF] = result == 0
|
||||
if .SF in flags do cpu.flags[.SF] = (result >> 15) & 0x1 == 1
|
||||
if .CF in flags {
|
||||
cpu.flags[.CF] = is_add ? u32(dst) + u32(src) > 0xFFFF : src > dst
|
||||
}
|
||||
|
||||
check_parity_flag :: proc(cpu: ^Cpu, value: i16) {
|
||||
val := value
|
||||
if .AF in flags {
|
||||
lhs, rhs := dst & 0xF, src & 0xF
|
||||
cpu.flags[.AF] = is_add ? lhs + rhs > 15 : lhs < rhs
|
||||
}
|
||||
if .PF in flags {
|
||||
val := result
|
||||
bit_count := 0
|
||||
val &= 0x00FF
|
||||
for val != 0 {
|
||||
@ -91,84 +78,32 @@ check_parity_flag :: proc(cpu: ^Cpu, value: i16) {
|
||||
}
|
||||
cpu.flags[.PF] = bit_count % 2 == 0
|
||||
}
|
||||
|
||||
check_auxiliary_carry_flag :: proc(cpu: ^Cpu, dst: i16, src: i16, is_add: bool) {
|
||||
lhs, rhs := dst & 0xF, src & 0xF
|
||||
cpu.flags[.AF] = is_add ? lhs + rhs > 15 : lhs < rhs
|
||||
}
|
||||
|
||||
check_flags :: proc(cpu: ^Cpu, value: i16) {
|
||||
check_zero_flag(cpu, value)
|
||||
check_sign_flag(cpu, value)
|
||||
check_parity_flag(cpu, value)
|
||||
perform_store :: proc(cpu: ^Cpu, value: i16, operand: Operand, is_word: bool) {
|
||||
#partial switch opr in operand {
|
||||
case RegisterId:
|
||||
switch opr.access {
|
||||
case .Low:
|
||||
cpu.registers[opr.name].low = u8(value)
|
||||
case .High:
|
||||
cpu.registers[opr.name].high = u8(value)
|
||||
case .Full:
|
||||
cpu.registers[opr.name].full = i16(value)
|
||||
}
|
||||
case DirectAddress:
|
||||
cpu.memory[opr] = u8(value)
|
||||
if is_word do cpu.memory[opr+1] = u8((u16(value) & 0xFF00) >> 8)
|
||||
case MemoryAddr:
|
||||
effective_addr_val := get_effective_address_value(cpu, opr.addr_id)
|
||||
addr := effective_addr_val + opr.displacement
|
||||
cpu.memory[addr] = u8(value)
|
||||
if is_word do cpu.memory[addr+1] = u8((u16(value) & 0xFF00) >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
execute_instruction :: proc(cpu: ^Cpu, inst: Instruction) {
|
||||
if reg,ok := inst.dst.(RegisterId); ok {
|
||||
#partial switch inst.opname {
|
||||
case .MOV:
|
||||
src_val := get_operand_value(cpu, inst.src)
|
||||
set_register_value(cpu, reg, src_val)
|
||||
case .ADD:
|
||||
src_val := get_operand_value(cpu, inst.src)
|
||||
dst_val := get_operand_value(cpu, inst.dst)
|
||||
val := i16(cpu.registers[reg.name].full) + src_val
|
||||
set_register_value(cpu, reg, val)
|
||||
check_flags(cpu, val)
|
||||
check_auxiliary_carry_flag(cpu, dst_val, src_val, true)
|
||||
check_carry_flag(cpu, dst_val, src_val, true)
|
||||
case .SUB:
|
||||
src_val := get_operand_value(cpu, inst.src)
|
||||
dst_val := get_operand_value(cpu, inst.dst)
|
||||
val := i16(cpu.registers[reg.name].full) - src_val
|
||||
set_register_value(cpu, reg, val)
|
||||
check_flags(cpu, val)
|
||||
check_auxiliary_carry_flag(cpu, dst_val, src_val, false)
|
||||
check_carry_flag(cpu, dst_val, src_val, false)
|
||||
case .CMP:
|
||||
src_val := get_operand_value(cpu, inst.src)
|
||||
dst_val := get_operand_value(cpu, inst.dst)
|
||||
val := i16(cpu.registers[reg.name].full) - src_val
|
||||
check_flags(cpu, val)
|
||||
check_auxiliary_carry_flag(cpu, dst_val, src_val, false)
|
||||
check_carry_flag(cpu, dst_val, src_val, false)
|
||||
}
|
||||
} else if addr,ok := inst.dst.(DirectAddress); ok {
|
||||
#partial switch inst.opname {
|
||||
case .MOV:
|
||||
if imm,ok := inst.src.(Immediate); ok {
|
||||
if imm.size == ._16 {
|
||||
cpu.memory[addr] = u8(imm.value & 0x00FF)
|
||||
cpu.memory[addr+1] = u8((u16(imm.value) & 0xFF00) >> 8)
|
||||
} else {
|
||||
cpu.memory[addr] = u8(imm.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if mem_addr,ok := inst.dst.(MemoryAddr); ok {
|
||||
#partial switch inst.opname {
|
||||
case .MOV:
|
||||
value := get_operand_value(cpu, inst.src)
|
||||
|
||||
effective_addr_val := get_effective_address_value(cpu, mem_addr.addr_id)
|
||||
addr := effective_addr_val + mem_addr.displacement
|
||||
cpu.memory[addr] = u8(value & 0x00FF)
|
||||
cpu.memory[addr+1] = u8((u16(value) & 0xFF00) >> 8)
|
||||
|
||||
// TODO: We need a way to detect if it's a byte or a word
|
||||
// if imm,ok := inst.src.(Immediate); ok {
|
||||
// // TODO: We need a function that returns the registers to check out
|
||||
// effective_addr_val := get_effective_address_value(cpu, mem_addr.addr_id)
|
||||
// addr := effective_addr_val + mem_addr.displacement_value
|
||||
// if imm.size == .Signed16 {
|
||||
// cpu.memory[addr] = u8(imm.value & 0x00FF)
|
||||
// cpu.memory[addr+1] = u8((u16(imm.value) & 0xFF00) >> 8)
|
||||
// } else {
|
||||
// cpu.memory[addr] = u8(imm.value)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
} else if jmp_offset,ok := inst.src.(Jump); ok {
|
||||
if jmp_offset,ok := inst.src.(Jump); ok {
|
||||
jump: bool
|
||||
#partial switch inst.opname {
|
||||
case .JNZ, .JNE: jump = !cpu.flags[.ZF]
|
||||
@ -187,6 +122,30 @@ execute_instruction :: proc(cpu: ^Cpu, inst: Instruction) {
|
||||
cpu.registers[.ip].full += i16(jmp_offset)
|
||||
cpu.registers[.ip].full -= i16(inst.bytes_read)
|
||||
}
|
||||
return
|
||||
}
|
||||
status_flags := bit_set[Flag]{.OF, .SF, .ZF, .AF, .PF, .CF}
|
||||
#partial switch inst.opname {
|
||||
case .MOV:
|
||||
src_val := perform_load(cpu, inst.src, inst.is_word)
|
||||
perform_store(cpu, src_val, inst.dst, inst.is_word)
|
||||
case .ADD:
|
||||
src_val := perform_load(cpu, inst.src, inst.is_word)
|
||||
dst_val := perform_load(cpu, inst.dst, inst.is_word)
|
||||
val := dst_val + src_val
|
||||
perform_store(cpu, val, inst.dst, inst.is_word)
|
||||
check_flags(cpu, status_flags, dst_val, src_val, val, true)
|
||||
case .SUB:
|
||||
src_val := perform_load(cpu, inst.src, inst.is_word)
|
||||
dst_val := perform_load(cpu, inst.dst, inst.is_word)
|
||||
val := dst_val - src_val
|
||||
perform_store(cpu, val, inst.dst, inst.is_word)
|
||||
check_flags(cpu, status_flags, dst_val, src_val, val, false)
|
||||
case .CMP:
|
||||
src_val := perform_load(cpu, inst.src, inst.is_word)
|
||||
dst_val := perform_load(cpu, inst.dst, inst.is_word)
|
||||
val := dst_val - src_val
|
||||
check_flags(cpu, status_flags, dst_val, src_val, val, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ get_operand_string :: proc(operand: Operand, has_segment: Maybe(RegisterId)) ->
|
||||
case RegisterId:
|
||||
string_val = get_register_name(val)
|
||||
case Immediate:
|
||||
string_val = fmt.aprintf("%d", i16(val.value))
|
||||
string_val = fmt.aprintf("%d", val.value)
|
||||
case MemoryAddr:
|
||||
string_val = get_memory_string(val, has_segment)
|
||||
case DirectAddress:
|
||||
|
@ -7,6 +7,11 @@ import "core:strings"
|
||||
import "core:strconv"
|
||||
import "core:reflect"
|
||||
|
||||
get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue {
|
||||
reg,_ := reflect.enum_from_name(Register, name)
|
||||
return &cpu.registers[reg]
|
||||
}
|
||||
|
||||
parse_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) {
|
||||
cpu: Cpu
|
||||
|
||||
|
@ -68,6 +68,7 @@ Immediate :: struct {
|
||||
MemoryAddr :: struct {
|
||||
addr_id: u8,
|
||||
displacement: i16,
|
||||
disp_size: ImmediateSize,
|
||||
}
|
||||
DirectAddress :: distinct i16
|
||||
Jump :: distinct i8
|
||||
@ -119,6 +120,7 @@ InstructionInfo :: struct {
|
||||
desc: string,
|
||||
src: OperandInfo,
|
||||
dst: OperandInfo,
|
||||
flags: bit_set[Flag],
|
||||
word_size: WordSize,
|
||||
reg_info: RegisterEncodingBits,
|
||||
has_flip: bool,
|
||||
|
Loading…
x
Reference in New Issue
Block a user