Compare commits
2 Commits
08874c4533
...
5cf4768b80
Author | SHA1 | Date | |
---|---|---|---|
5cf4768b80 | |||
cd5eada115 |
36
asm_files/list-0047.asm
Normal file
36
asm_files/list-0047.asm
Normal file
@ -0,0 +1,36 @@
|
||||
; ========================================================================
|
||||
;
|
||||
; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved.
|
||||
;
|
||||
; This software is provided 'as-is', without any express or implied
|
||||
; warranty. In no event will the authors be held liable for any damages
|
||||
; arising from the use of this software.
|
||||
;
|
||||
; Please see https://computerenhance.com for further information
|
||||
;
|
||||
; ========================================================================
|
||||
|
||||
; ========================================================================
|
||||
; LISTING 47
|
||||
; ========================================================================
|
||||
|
||||
bits 16
|
||||
|
||||
add bx, 30000
|
||||
add bx, 10000
|
||||
sub bx, 5000
|
||||
sub bx, 5000
|
||||
|
||||
mov bx, 1
|
||||
mov cx, 100
|
||||
add bx, cx
|
||||
|
||||
mov dx, 10
|
||||
sub cx, dx
|
||||
|
||||
add bx, 40000
|
||||
add cx, -90
|
||||
|
||||
mov sp, 99
|
||||
mov bp, 98
|
||||
cmp bp, sp
|
22
asm_files/list-0047.txt
Normal file
22
asm_files/list-0047.txt
Normal file
@ -0,0 +1,22 @@
|
||||
--- test\listing_0047_challenge_flags execution ---
|
||||
add bx, 30000 ; bx:0x0->0x7530 flags:->P
|
||||
add bx, 10000 ; bx:0x7530->0x9c40 flags:P->SO
|
||||
sub bx, 5000 ; bx:0x9c40->0x88b8 flags:SO->PAS
|
||||
sub bx, 5000 ; bx:0x88b8->0x7530 flags:PAS->PO
|
||||
mov bx, 1 ; bx:0x7530->0x1
|
||||
mov cx, 100 ; cx:0x0->0x64
|
||||
add bx, cx ; bx:0x1->0x65 flags:PO->P
|
||||
mov dx, 10 ; dx:0x0->0xa
|
||||
sub cx, dx ; cx:0x64->0x5a flags:P->PA
|
||||
add bx, 40000 ; bx:0x65->0x9ca5 flags:PA->PS
|
||||
add cx, -90 ; cx:0x5a->0x0 flags:PS->CPAZ
|
||||
mov sp, 99 ; sp:0x0->0x63
|
||||
mov bp, 98 ; bp:0x0->0x62
|
||||
cmp bp, sp ; flags:CPAZ->CPAS
|
||||
|
||||
Final registers:
|
||||
bx: 0x9ca5 (40101)
|
||||
dx: 0x000a (10)
|
||||
sp: 0x0063 (99)
|
||||
bp: 0x0062 (98)
|
||||
flags: CPAS
|
@ -80,11 +80,11 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
|
||||
case .SecondByteLast3: reg = data[1] & 0b111
|
||||
}
|
||||
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 {
|
||||
operand = RegisterId { idx = (int)(reg), access = .Full }
|
||||
operand = RegisterId { name = Register(reg), access = .Full }
|
||||
} 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:
|
||||
mod := data[1] >> 6
|
||||
@ -107,9 +107,9 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
|
||||
processed^ += 2
|
||||
} else if mod == 3 {
|
||||
if word {
|
||||
op = RegisterId { idx = (int)(rm), access = .Full }
|
||||
op = RegisterId { name = Register(rm), access = .Full }
|
||||
} 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
|
||||
@ -126,7 +126,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr
|
||||
operand = Immediate { value = u16(data[processed^]), size = .Unsigned8 }
|
||||
processed^ += 1
|
||||
case .Accumulator:
|
||||
operand = RegisterId { idx = 0, access = word ? .Full : .Low }
|
||||
operand = RegisterId { name = Register(0), access = word ? .Full : .Low }
|
||||
case .DirectAddress:
|
||||
// operand = DirectAddress { value = 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
|
||||
operand = (Jump)((i8)(data[1]) + 2)
|
||||
case .VariablePort:
|
||||
operand = RegisterId { idx = (int)(Register.dx), access = .Full }
|
||||
operand = RegisterId { name = Register.dx, access = .Full }
|
||||
case .ShiftRotate:
|
||||
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:
|
||||
bits := (data[1] & 0b1110) >> 1
|
||||
w := (data[1] & 0b1) == 1 ? "w" : "b"
|
||||
@ -203,7 +203,7 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
|
||||
continue
|
||||
} else if inst.opname == .SEGMENT {
|
||||
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
|
||||
continue
|
||||
} else if inst.opname == .AAM {
|
||||
|
@ -11,7 +11,7 @@ get_operand_value :: proc(operand: Operand) -> u16 {
|
||||
case Immediate:
|
||||
return opr.value
|
||||
case RegisterId:
|
||||
reg_val := CPU.registers[opr.idx]
|
||||
reg_val := CPU.registers[opr.name]
|
||||
switch opr.access {
|
||||
case .Low, .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) {
|
||||
switch reg.access {
|
||||
case .Low:
|
||||
CPU.registers[reg.idx].low = u8(value)
|
||||
CPU.registers[reg.name].low = u8(value)
|
||||
case .High:
|
||||
CPU.registers[reg.idx].high = u8(value)
|
||||
CPU.registers[reg.name].high = u8(value)
|
||||
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 {
|
||||
reg,_ := reflect.enum_from_name(Register, name)
|
||||
return &cpu.registers[int(reg)]
|
||||
return &cpu.registers[reg]
|
||||
}
|
||||
|
||||
check_zero_flag :: proc(value: u16) {
|
||||
CPU.flags.ZF = value == 0
|
||||
CPU.flags[.ZF] = value == 0
|
||||
}
|
||||
|
||||
check_sign_flag :: proc(value: u16) {
|
||||
CPU.flags.SF = value >> 15 == 1
|
||||
CPU.flags[.SF] = value >> 15 == 1
|
||||
}
|
||||
|
||||
execute_instruction :: proc(inst: Instruction) {
|
||||
@ -54,19 +54,19 @@ execute_instruction :: proc(inst: Instruction) {
|
||||
set_register_value(reg, src_val)
|
||||
case .ADD:
|
||||
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)
|
||||
check_zero_flag(val)
|
||||
check_sign_flag(val)
|
||||
case .SUB:
|
||||
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)
|
||||
check_zero_flag(val)
|
||||
check_sign_flag(val)
|
||||
case .CMP:
|
||||
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_sign_flag(val)
|
||||
}
|
||||
|
@ -78,9 +78,9 @@ get_register_name :: proc(reg_id: RegisterId) -> string {
|
||||
low_names := [?]string{"al", "cl", "dl", "bl"}
|
||||
high_names := [?]string{"ah", "ch", "dh", "bh"}
|
||||
switch reg_id.access {
|
||||
case .Full: return reflect.enum_string(Register(reg_id.idx))
|
||||
case .Low: return low_names[reg_id.idx]
|
||||
case .High: return high_names[reg_id.idx % 4]
|
||||
case .Full: return reflect.enum_string(reg_id.name)
|
||||
case .Low: return low_names[int(reg_id.name)]
|
||||
case .High: return high_names[int(reg_id.name) % 4]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
31
sim8086.odin
31
sim8086.odin
@ -5,6 +5,7 @@ import path "core:path/filepath"
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:strings"
|
||||
import "core:reflect"
|
||||
|
||||
CPU := Cpu {
|
||||
memory = make([dynamic]u8, 65536),
|
||||
@ -42,21 +43,31 @@ main :: proc() {
|
||||
}
|
||||
|
||||
if what_to_print == "registers" || what_to_print == "all" {
|
||||
for reg,i in CPU.registers {
|
||||
full := fmt.aprintf("%s: %d ", get_register_name(RegisterId{idx=i}), reg.full)
|
||||
hex := fmt.aprintf("0x%04x ", reg.full)
|
||||
fmt.println("\nRegisters")
|
||||
for reg_val,name in CPU.registers {
|
||||
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",
|
||||
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("\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)
|
||||
expected_cpu,_ := extract_expected_cpu_state(path)
|
||||
for reg,i in expected_cpu.registers {
|
||||
if CPU.registers[i].full != reg.full {
|
||||
name := get_register_name(RegisterId{idx=i})
|
||||
msg := "%s register does not match - Expected %04x | Actual %04x"
|
||||
fmt.eprintfln(msg, name, reg.full, CPU.registers[i].full)
|
||||
ref_cpu,_ := extract_reference_cpu_state(path)
|
||||
for reg_val,name in ref_cpu.registers {
|
||||
if CPU.registers[name].full != reg_val.full {
|
||||
msg := "%s register does not match reference - Expected %04x | Actual %04x"
|
||||
fmt.eprintfln(msg, name, reg_val.full, CPU.registers[name].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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
testing.odin
16
testing.odin
@ -5,8 +5,9 @@ import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:strings"
|
||||
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
|
||||
|
||||
data,ok := os.read_entire_file(filename)
|
||||
@ -27,7 +28,18 @@ extract_expected_cpu_state :: proc(filename: string) -> (Cpu, bool) {
|
||||
} else if c == ' ' {
|
||||
space_count += 1
|
||||
} 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_value := get_cpu_register_by_name(&cpu, reg_name)
|
||||
hex_string := line[i+6:i+10]
|
||||
|
21
types.odin
21
types.odin
@ -22,9 +22,18 @@ RegisterValue :: struct #raw_union {
|
||||
full: u16,
|
||||
}
|
||||
|
||||
Flags :: struct {
|
||||
ZF: bool,
|
||||
SF: bool,
|
||||
Flag :: enum {
|
||||
OF,
|
||||
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 {
|
||||
@ -51,7 +60,7 @@ RegisterAccess :: enum {
|
||||
}
|
||||
|
||||
RegisterId :: struct {
|
||||
idx: int,
|
||||
name: Register,
|
||||
access: RegisterAccess,
|
||||
}
|
||||
ImmediateSize :: enum {
|
||||
@ -144,8 +153,8 @@ Instruction :: struct {
|
||||
}
|
||||
|
||||
Cpu :: struct {
|
||||
flags: Flags,
|
||||
registers: [12]RegisterValue,
|
||||
flags: [Flag]bool,
|
||||
registers: [Register]RegisterValue,
|
||||
memory: [dynamic]u8,
|
||||
total_bytes_processed: int
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user