Compare commits
3 Commits
a91c3d9ba9
...
266f7a7900
Author | SHA1 | Date | |
---|---|---|---|
266f7a7900 | |||
863ccfc583 | |||
fd8f696627 |
28
asm_files/list-0046.asm
Normal file
28
asm_files/list-0046.asm
Normal 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
24
asm_files/list-0046.txt
Normal 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
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
13
types.odin
13
types.odin
@ -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,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user