Compare commits

...

3 Commits

9 changed files with 204 additions and 38 deletions

28
asm_files/list-0046.asm Normal file
View File

@ -0,0 +1,28 @@
; ========================================================================
;
; (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 46
; ========================================================================
bits 16
mov bx, -4093
mov cx, 3841
sub bx, cx
mov sp, 998
mov bp, 999
cmp bp, sp
add bp, 1027
sub bp, 2026

24
asm_files/list-0046.txt Normal file
View File

@ -0,0 +1,24 @@
--- test\listing_0046_add_sub_cmp execution ---
mov bx, 61443 ; bx:0x0->0xf003
mov cx, 3841 ; cx:0x0->0xf01
sub bx, cx ; bx:0xf003->0xe102 flags:->S
mov sp, 998 ; sp:0x0->0x3e6
mov bp, 999 ; bp:0x0->0x3e7
cmp bp, sp ; flags:S->
add bp, 1027 ; bp:0x3e7->0x7ea
sub bp, 2026 ; bp:0x7ea->0x0 flags:->PZ
Final registers:
bx: 0xe102 (57602)
cx: 0x0f01 (3841)
sp: 0x03e6 (998)
ax: 0x0000 (0)
bp: 0x0000 (0)
dx: 0x0000 (0)
si: 0x0000 (0)
di: 0x0000 (0)
es: 0x0000 (0)
ss: 0x0000 (0)
cs: 0x0000 (0)
ds: 0x0000 (0)
flags: PZ

View File

@ -4,6 +4,64 @@ import "core:fmt"
import "core:math"
import "core:strings"
get_op :: proc(inst: Instruction) -> (Op, bool) {
op: Op
interseg: bool
if inst.opname == .TBD2 {
switch inst.raw_data[1] & 0b00111000 >> 3 {
case 0b000: op = .INC
case 0b001: op = .DEC
case 0b010: op = .CALL
// TODO: We really have to fix this because we shouldn't be figuring out if this
// is an intersegment here
case 0b011: op = .CALL; interseg = true
case 0b100: op = .JMP
case 0b101: op = .JMP; interseg = true
case 0b110: op = .PUSH
}
} else if inst.opname == .TBD5 {
switch inst.raw_data[1] & 0b00111000 >> 3 {
case 0b000: op = .TEST
case 0b001: op = .DEC
case 0b010: op = .NOT
case 0b011: op = .NEG
case 0b100: op = .MUL
case 0b101: op = .IMUL
case 0b110: op = .DIV
case 0b111: op = .IDIV
}
} else if inst.opname == .TBD6 {
switch inst.raw_data[1] & 0b00111000 >> 3 {
case 0b000: op = .ROL
case 0b001: op = .ROR
case 0b010: op = .RCL
case 0b011: op = .RCR
case 0b100: op = .SHL
case 0b101: op = .SHR
case 0b111: op = .SAR
}
} else if inst.opname == .TBD1 || inst.opname == .TBD3 || inst.opname == .TBD4 {
bits: u8
if inst.opname == .TBD1 || inst.opname == .TBD3 {
bits = inst.raw_data[0] & 0b00111000 >> 3
} else {
bits = inst.raw_data[1] & 0b00111000 >> 3
}
switch bits {
case 0b000: op = .ADD
case 0b001: op = .OR
case 0b010: op = .ADC
case 0b011: op = .SBB
case 0b100: op = .AND
case 0b101: op = .SUB
case 0b110: op = .XOR
case 0b111: op = .CMP
}
} else {
op = inst.opname
}
return op, interseg
}
parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, processed: ^int, word: bool, has_segreg: Maybe(Register)) -> Operand {
operand: Operand = None{}
switch opinfo {
@ -163,7 +221,6 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
processed += inst.consume_extra_bytes
instruction.opname = inst.opname
instruction.src = src_opr
instruction.dst = dst_opr
instruction.is_word = word
@ -173,6 +230,8 @@ decode_data :: proc(inst_list: ^[dynamic]Instruction, data: []u8, bytes_to_read:
instruction.info = inst
instruction.has_lock = has_lock
instruction.has_segment = has_segment
instruction.opname = inst.opname
instruction.opname,instruction.indirect_intersegment = get_op(instruction)
// fmt.println(parsed_inst)
append(inst_list, instruction)

View File

@ -5,36 +5,64 @@ import "core:fmt"
import "core:math"
import "core:strings"
get_operand_value :: proc(operand: Operand) -> u16 {
#partial switch opr in operand {
case Immediate:
return opr.value
case RegisterId:
switch opr.access {
case .Low, .High:
val := opr.access == .Low ? registers[opr.id].value.low : registers[opr.id].value.high
return u16(val)
case .Full:
return registers[opr.id].value.full
}
}
return 0
}
set_register_value :: proc(reg_id: RegisterId, value: u16) {
switch reg_id.access {
case .Low:
registers[reg_id.id].value.low = u8(value)
case .High:
registers[reg_id.id].value.high = u8(value)
case .Full:
registers[reg_id.id].value.full = u16(value)
}
}
check_zero_flag :: proc(value: u16) {
CPU.flags.ZF = value == 0
}
check_sign_flag :: proc(value: u16) {
CPU.flags.SF = value >> 15 == 1
}
execute_instruction :: proc(inst: Instruction) {
#partial switch inst.opname {
if reg,ok := inst.dst.(RegisterId); ok {
#partial switch inst.opname {
case .MOV:
if reg_id,ok := inst.dst.(RegisterId); ok {
// val := registers[reg_id.id].value.full
#partial switch val in inst.src {
case Immediate:
if val.size == .Signed16 {
registers[reg_id.id].value.full = (u16)(val.value)
} else {
value := u8(val.value & 0xFF)
if reg_id.access == .Low {
registers[reg_id.id].value.low = value
} else {
registers[reg_id.id].value.high = value
}
}
case RegisterId:
switch val.access {
case .Low, .High:
value := val.access == .Low ? registers[val.id].value.low : registers[val.id].value.high
if reg_id.access == .Low {
registers[reg_id.id].value.low = value
} else {
registers[reg_id.id].value.high = value
}
case .Full:
registers[reg_id.id].value.full = registers[val.id].value.full
}
}
src_val := get_operand_value(inst.src)
set_register_value(reg, src_val)
case .ADD:
src_val := get_operand_value(inst.src)
val := registers[reg.id].value.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 := registers[reg.id].value.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 := registers[reg.id].value.full - src_val
check_zero_flag(val)
check_sign_flag(val)
}
}
}

View File

@ -31,6 +31,8 @@ Op :: enum {
SBB,
DEC,
NEG,
MUL,
IMUL,
CMP,
AAS,
DAS,
@ -40,8 +42,18 @@ Op :: enum {
AAD,
CBW,
CWD,
ROL,
ROR,
RCL,
RCR,
SHL,
SHR,
SAR,
NOT,
TEST,
OR,
AND,
XOR,
REP,
RET,
RETF,

View File

@ -194,16 +194,12 @@ get_instruction_string :: proc(inst_info: InstructionInfo, instruction: Instruct
src_str := get_operand_string(inst.src, inst.has_segment)
opname: string
is_interseg: bool
if inst_info.check_second_encoding {
opname,is_interseg = get_opname(inst)
} else {
// TODO: Do the RTTI thing here with reflection
opname = strings.to_lower(fmt.aprintf("%s", inst.opname))
}
// TODO: Do the RTTI thing here with reflection
opname = strings.to_lower(fmt.aprintf("%s", inst.opname))
if dst_str == "" {
interseg_string: string
if is_interseg {
if instruction.indirect_intersegment {
interseg_string = " far"
}
fmt.sbprintf(&instruction_builder, "%s%s %s%s", opname, interseg_string, size_string, src_str)

View File

@ -30,6 +30,11 @@ registers := [?]Register {
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

View File

@ -19,5 +19,10 @@ do
./sim8086 asm_files/${asm_listing}.bin registers | awk '{print $1 $4}' | sort > temp1
cat $asm_txt | awk '/Final registers/,0' | tail -n +2 | awk '{print $1 $2}' | sort > temp2
diff -U0 --color temp1 temp2
if [ $? -eq 1 ]; then
echo Listing $asm_listing Failed!
else
echo Listing $asm_listing Succeded!
fi
done
rm temp1 temp2

View File

@ -11,6 +11,11 @@ Register :: struct {
code: u8,
}
Flags :: struct {
ZF: bool,
SF: bool,
}
WordSize :: enum {
None,
LastBit,
@ -20,7 +25,6 @@ WordSize :: enum {
}
None :: struct {}
Disp8 :: i8
Disp16 :: i16
Displacement :: union {
@ -118,7 +122,7 @@ Instruction :: struct {
dst: Operand,
info: InstructionInfo,
is_word: bool,
// indirect_intersegment: bool,
indirect_intersegment: bool,
// TODO: This is trickier than I thought, it's more than just the one instruction
// that uses it
has_segment: Maybe(Register),
@ -127,3 +131,8 @@ Instruction :: struct {
raw_data: []u8,
debug_msg: string,
}
Cpu :: struct {
flags: Flags,
memory: [dynamic]u8,
}