Compare commits
No commits in common. "2a5b3461e32c398d042eb414c3d015f44568b017" and "5ae2cc3a566ef891e9fda1b48fa79f4ad611a2d9" have entirely different histories.
2a5b3461e3
...
5ae2cc3a56
@ -85,10 +85,3 @@ copy /Y %script_dir%\%listing_0046%.txt %build_dir% 1>NUL
|
|||||||
set build_dir_listing_0046=%build_dir%\%listing_0046%
|
set build_dir_listing_0046=%build_dir%\%listing_0046%
|
||||||
%build_dir%\sim8086.exe --exec %build_dir_listing_0046% > %build_dir_listing_0046%_disassembled.txt
|
%build_dir%\sim8086.exe --exec %build_dir_listing_0046% > %build_dir_listing_0046%_disassembled.txt
|
||||||
fc /N %build_dir_listing_0046%.txt %build_dir_listing_0046%_disassembled.txt || exit /b 1
|
fc /N %build_dir_listing_0046%.txt %build_dir_listing_0046%_disassembled.txt || exit /b 1
|
||||||
|
|
||||||
set listing_0047=listing_0047_challenge_flags
|
|
||||||
copy /Y %script_dir%\%listing_0047% %build_dir% 1>NUL
|
|
||||||
copy /Y %script_dir%\%listing_0047%.txt %build_dir% 1>NUL
|
|
||||||
set build_dir_listing_0047=%build_dir%\%listing_0047%
|
|
||||||
%build_dir%\sim8086.exe --exec %build_dir_listing_0047% > %build_dir_listing_0047%_disassembled.txt
|
|
||||||
fc /N %build_dir_listing_0047%.txt %build_dir_listing_0047%_disassembled.txt || exit /b 1
|
|
||||||
|
Binary file not shown.
@ -1,36 +0,0 @@
|
|||||||
; ========================================================================
|
|
||||||
;
|
|
||||||
; (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
|
|
@ -1,23 +0,0 @@
|
|||||||
--- 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
|
|
||||||
|
|
303
part1/sim8086.c
303
part1/sim8086.c
@ -1,13 +1,3 @@
|
|||||||
#define WIN32_MEAN_AND_LEAN
|
|
||||||
#define NOMINMAX
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <immintrin.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "sim8086_stdlib.h"
|
#include "sim8086_stdlib.h"
|
||||||
#include "sim8086.h"
|
#include "sim8086.h"
|
||||||
|
|
||||||
@ -22,20 +12,15 @@ typedef enum S86_RegisterByte {
|
|||||||
|
|
||||||
typedef union S86_Register16 {
|
typedef union S86_Register16 {
|
||||||
uint16_t word;
|
uint16_t word;
|
||||||
|
struct { uint8_t lo; uint8_t hi; } byte;
|
||||||
uint8_t bytes[S86_RegisterByte_Count];
|
uint8_t bytes[S86_RegisterByte_Count];
|
||||||
} S86_Register16;
|
} S86_Register16;
|
||||||
|
|
||||||
typedef struct S86_RegisterFileFlags {
|
|
||||||
bool carry;
|
|
||||||
bool zero;
|
|
||||||
bool sign;
|
|
||||||
bool overflow;
|
|
||||||
bool parity;
|
|
||||||
bool auxiliary_carry;
|
|
||||||
} S86_RegisterFileFlags;
|
|
||||||
|
|
||||||
typedef struct S86_RegisterFile {
|
typedef struct S86_RegisterFile {
|
||||||
S86_RegisterFileFlags flags;
|
bool zero_flag;
|
||||||
|
bool sign_flag;
|
||||||
|
bool parity_flag;
|
||||||
|
bool overflow_flag;
|
||||||
|
|
||||||
S86_Register16 ax;
|
S86_Register16 ax;
|
||||||
S86_Register16 bx;
|
S86_Register16 bx;
|
||||||
@ -53,17 +38,6 @@ typedef struct S86_RegisterFile {
|
|||||||
S86_Register16 ds;
|
S86_Register16 ds;
|
||||||
} S86_RegisterFile;
|
} S86_RegisterFile;
|
||||||
|
|
||||||
bool S86_RegisterFileFlagsEq(S86_RegisterFileFlags lhs, S86_RegisterFileFlags rhs)
|
|
||||||
{
|
|
||||||
bool result = lhs.carry == rhs.carry &&
|
|
||||||
lhs.zero == rhs.zero &&
|
|
||||||
lhs.sign == rhs.sign &&
|
|
||||||
lhs.overflow == rhs.overflow &&
|
|
||||||
lhs.parity == rhs.parity &&
|
|
||||||
lhs.auxiliary_carry == rhs.auxiliary_carry;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
S86_Str8 S86_MnemonicStr8(S86_Mnemonic type)
|
S86_Str8 S86_MnemonicStr8(S86_Mnemonic type)
|
||||||
{
|
{
|
||||||
S86_Str8 result = {0};
|
S86_Str8 result = {0};
|
||||||
@ -281,11 +255,7 @@ void S86_PrintOpcodeMnemonicOp(S86_Opcode opcode, bool src)
|
|||||||
opcode.displacement > 0 ? '+' : '-',
|
opcode.displacement > 0 ? '+' : '-',
|
||||||
opcode.displacement > 0 ? opcode.displacement : -opcode.displacement);
|
opcode.displacement > 0 ? opcode.displacement : -opcode.displacement);
|
||||||
} else if (mnemonic_op == S86_MnemonicOp_Immediate) {
|
} else if (mnemonic_op == S86_MnemonicOp_Immediate) {
|
||||||
if (opcode.immediate_is_8bit) {
|
S86_PrintFmt("%u", opcode.immediate);
|
||||||
S86_PrintFmt("%d", (int8_t)opcode.immediate);
|
|
||||||
} else {
|
|
||||||
S86_PrintFmt("%u", (uint16_t)opcode.immediate);
|
|
||||||
}
|
|
||||||
} else if (mnemonic_op == S86_MnemonicOp_DirectInterSegment) {
|
} else if (mnemonic_op == S86_MnemonicOp_DirectInterSegment) {
|
||||||
uint16_t left = (uint32_t)opcode.displacement >> 16;
|
uint16_t left = (uint32_t)opcode.displacement >> 16;
|
||||||
uint16_t right = (uint32_t)opcode.displacement & 0xFFFF;
|
uint16_t right = (uint32_t)opcode.displacement & 0xFFFF;
|
||||||
@ -630,14 +600,8 @@ S86_Opcode S86_DecodeOpcode(S86_BufferIterator *buffer_it,
|
|||||||
op_decode_type == S86_OpDecodeType_TESTImmediateAndRegOrMem ||
|
op_decode_type == S86_OpDecodeType_TESTImmediateAndRegOrMem ||
|
||||||
op_decode_type == S86_OpDecodeType_ORImmediateToRegOrMem ||
|
op_decode_type == S86_OpDecodeType_ORImmediateToRegOrMem ||
|
||||||
op_decode_type == S86_OpDecodeType_XORImmediateToRegOrMem) && s) {
|
op_decode_type == S86_OpDecodeType_XORImmediateToRegOrMem) && s) {
|
||||||
// NOTE: Sign extend 8 bit to 16 bit
|
// NOTE: Sign extend 8 bit, since we store into a
|
||||||
uint16_t sign_mask = 0b1000'0000;
|
// int32_t in opcode this is done for free for us.
|
||||||
uint8_t data_u8 = S86_CAST(uint8_t)data;
|
|
||||||
if (sign_mask & data_u8) {
|
|
||||||
data = (uint16_t)((uint8_t)~data_u8 + 1); // Convert back to 8 bit unsigned
|
|
||||||
data = ~data + 1; // Convert to 16bit signed
|
|
||||||
result.immediate_is_8bit = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
uint8_t data_hi = S86_BufferIteratorNextByte(buffer_it);
|
uint8_t data_hi = S86_BufferIteratorNextByte(buffer_it);
|
||||||
data |= (uint16_t)(data_hi) << 8;
|
data |= (uint16_t)(data_hi) << 8;
|
||||||
@ -648,16 +612,8 @@ S86_Opcode S86_DecodeOpcode(S86_BufferIterator *buffer_it,
|
|||||||
S86_ASSERT(mod != 0b11); // NOTE: Op is IMM->Reg, register-to-register not permitted
|
S86_ASSERT(mod != 0b11); // NOTE: Op is IMM->Reg, register-to-register not permitted
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Sign extend 16bit to 32bit
|
result.immediate = data;
|
||||||
uint16_t sign_mask16 = 0b1000'0000'0000'0000;
|
result.src = S86_MnemonicOp_Immediate;
|
||||||
if (data & sign_mask16) {
|
|
||||||
uint32_t data_no_sign_bit = (uint32_t)((uint16_t)~data + 1); // Convert back to 16 bit unsigned
|
|
||||||
result.immediate = ~data_no_sign_bit + 1; // Convert to signed 32bit
|
|
||||||
} else {
|
|
||||||
result.immediate = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.src = S86_MnemonicOp_Immediate;
|
|
||||||
if (op_decode_type == S86_OpDecodeType_MOVImmediateToRegOrMem)
|
if (op_decode_type == S86_OpDecodeType_MOVImmediateToRegOrMem)
|
||||||
result.wide_prefix = S86_WidePrefix_Src;
|
result.wide_prefix = S86_WidePrefix_Src;
|
||||||
else if (result.effective_addr_loads_mem)
|
else if (result.effective_addr_loads_mem)
|
||||||
@ -859,10 +815,10 @@ S86_Opcode S86_DecodeOpcode(S86_BufferIterator *buffer_it,
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct S86_MnemonicOpToRegisterFileMap {
|
typedef struct S86_MnemonicOpToRegisterFileMap {
|
||||||
S86_MnemonicOp mnemonic_op; ///< Register/op that the mnemonic is using
|
S86_MnemonicOp mnemonic_op; ///< Register/op that the mnemonic is using
|
||||||
S86_MnemonicOp mnemonic_op_reg16; ///< 16 bit register for the mnemonic op
|
S86_MnemonicOp mnemonic_op_reg16; ///< 16 bit register for the mnemonic op
|
||||||
S86_Register16 *reg; ///< Pointer to the register memory this mnemonic op is using
|
S86_Register16 *reg; ///< Pointer to the register memory this mnemonic op is using
|
||||||
S86_RegisterByte byte; ///< The 'byte' that the mnemonic operates on (hi, lo or nil e.g. word)
|
S86_RegisterByte byte; ///< The 'byte' that the mnemonic operates on (hi, lo or nil e.g. word)
|
||||||
} S86_MnemonicOpToRegisterFileMap;
|
} S86_MnemonicOpToRegisterFileMap;
|
||||||
|
|
||||||
#define PRINT_USAGE S86_PrintLn(S86_STR8("usage: sim8086.exe [--exec] <binary asm file>"))
|
#define PRINT_USAGE S86_PrintLn(S86_STR8("usage: sim8086.exe [--exec] <binary asm file>"))
|
||||||
@ -1251,7 +1207,8 @@ int main(int argc, char **argv)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
S86_RegisterFileFlags prev_flags = register_file.flags;
|
bool prev_sign_flag = register_file.sign_flag;
|
||||||
|
bool prev_zero_flag = register_file.zero_flag;
|
||||||
switch (opcode.mnemonic) {
|
switch (opcode.mnemonic) {
|
||||||
case S86_Mnemonic_PUSH: /*FALLTHRU*/
|
case S86_Mnemonic_PUSH: /*FALLTHRU*/
|
||||||
case S86_Mnemonic_POP: /*FALLTHRU*/
|
case S86_Mnemonic_POP: /*FALLTHRU*/
|
||||||
@ -1372,30 +1329,24 @@ int main(int argc, char **argv)
|
|||||||
S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(dest_reg16), prev_dest, dest_map->reg->word);
|
S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(dest_reg16), prev_dest, dest_map->reg->word);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case S86_Mnemonic_ADD: /*FALLTHRU*/
|
case S86_Mnemonic_ADD: {
|
||||||
case S86_Mnemonic_SUB: /*FALLTHRU*/
|
S86_MnemonicOpToRegisterFileMap const *dest_map = NULL;
|
||||||
case S86_Mnemonic_CMP: {
|
|
||||||
S86_MnemonicOpToRegisterFileMap *dest_map = NULL;
|
|
||||||
for (size_t index = 0; !dest_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) {
|
for (size_t index = 0; !dest_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) {
|
||||||
S86_MnemonicOpToRegisterFileMap *item = mnemonic_op_to_register_file_map + index;
|
S86_MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index;
|
||||||
if (item->mnemonic_op == opcode.dest)
|
if (item->mnemonic_op == opcode.dest)
|
||||||
dest_map = item;
|
dest_map = item;
|
||||||
}
|
}
|
||||||
S86_ASSERT(dest_map);
|
S86_ASSERT(dest_map);
|
||||||
|
|
||||||
bool subtract = opcode.mnemonic != S86_Mnemonic_ADD;
|
uint16_t prev_dest = dest_map->reg->word;
|
||||||
S86_Register16 dest = *dest_map->reg;
|
bool byte_op = opcode.dest >= S86_MnemonicOp_AL && opcode.dest <= S86_MnemonicOp_BH;
|
||||||
S86_Register16 prev_dest = dest;
|
|
||||||
bool byte_op = opcode.dest >= S86_MnemonicOp_AL && opcode.dest <= S86_MnemonicOp_BH;
|
|
||||||
|
|
||||||
uint16_t src = 0;
|
|
||||||
if (opcode.src == S86_MnemonicOp_Immediate) {
|
if (opcode.src == S86_MnemonicOp_Immediate) {
|
||||||
if (byte_op) {
|
if (byte_op) {
|
||||||
S86_ASSERT(opcode.immediate < S86_CAST(uint8_t)-1);
|
S86_ASSERT(opcode.immediate < S86_CAST(uint8_t)-1);
|
||||||
src = S86_CAST(uint8_t)opcode.immediate;
|
dest_map->reg->bytes[dest_map->byte] += S86_CAST(uint8_t)opcode.immediate;
|
||||||
} else {
|
} else {
|
||||||
S86_ASSERT(opcode.immediate < S86_CAST(uint16_t)-1);
|
S86_ASSERT(opcode.immediate < S86_CAST(uint16_t)-1);
|
||||||
src = S86_CAST(uint16_t)opcode.immediate;
|
dest_map->reg->word += S86_CAST(uint16_t)opcode.immediate;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
S86_MnemonicOpToRegisterFileMap const *src_map = NULL;
|
S86_MnemonicOpToRegisterFileMap const *src_map = NULL;
|
||||||
@ -1404,117 +1355,113 @@ int main(int argc, char **argv)
|
|||||||
if (item->mnemonic_op == opcode.src)
|
if (item->mnemonic_op == opcode.src)
|
||||||
src_map = item;
|
src_map = item;
|
||||||
}
|
}
|
||||||
src = byte_op ? src_map->reg->bytes[src_map->byte] : src_map->reg->word;
|
|
||||||
|
if (byte_op)
|
||||||
|
dest_map->reg->bytes[dest_map->byte] += src_map->reg->bytes[src_map->byte];
|
||||||
|
else
|
||||||
|
dest_map->reg->word += src_map->reg->word;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Overflow if the sign masks were initially the same,
|
S86_Str8 dest_reg16 = S86_MnemonicOpStr8(dest_map->mnemonic_op_reg16);
|
||||||
// but, after the operation the sign masked changed.
|
|
||||||
uint8_t const sign_mask8 = 0b1000'0000;
|
|
||||||
uint16_t const sign_mask16 = 0b1000'0000'0000'0000;
|
|
||||||
if (byte_op) {
|
|
||||||
uint8_t src_u8 = S86_CAST(uint8_t)src;
|
|
||||||
if (subtract)
|
|
||||||
src_u8 = ~src_u8 + 1;
|
|
||||||
|
|
||||||
uint8_t dest_u8 = dest.bytes[dest_map->byte];
|
register_file.sign_flag = dest_map->reg->word & (byte_op ? 0b0000'0000'1000'0000 : 0b1000'0000'0000'0000);
|
||||||
uint8_t new_dest_u8 = dest_u8 + src_u8;
|
S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(dest_reg16), prev_dest, dest_map->reg->word);
|
||||||
|
} break;
|
||||||
|
|
||||||
// NOTE: Overflow check
|
case S86_Mnemonic_SUB: {
|
||||||
bool initially_matching_sign_masks = (dest_u8 & sign_mask8) == (src_u8 & sign_mask8);
|
S86_MnemonicOpToRegisterFileMap const *dest_map = NULL;
|
||||||
bool sign_masks_changed = (dest_u8 & sign_mask8) != (new_dest_u8 & sign_mask8);
|
for (size_t index = 0; !dest_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) {
|
||||||
register_file.flags.overflow = initially_matching_sign_masks && sign_masks_changed;
|
S86_MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index;
|
||||||
|
if (item->mnemonic_op == opcode.dest)
|
||||||
|
dest_map = item;
|
||||||
|
}
|
||||||
|
S86_ASSERT(dest_map);
|
||||||
|
|
||||||
// NOTE: Carry check
|
uint16_t prev_dest = dest_map->reg->word;
|
||||||
register_file.flags.carry = subtract ? new_dest_u8 > dest_u8 : new_dest_u8 < dest_u8;
|
bool byte_op = opcode.dest >= S86_MnemonicOp_AL && opcode.dest <= S86_MnemonicOp_BH;
|
||||||
|
if (opcode.src == S86_MnemonicOp_Immediate) {
|
||||||
// NOTE: Auxiliary carry check
|
if (byte_op) {
|
||||||
uint8_t dest_u8_nibble_lo = dest_u8 & 0b0000'1111 >> 0;
|
S86_ASSERT(opcode.immediate < S86_CAST(uint8_t)-1);
|
||||||
uint8_t dest_u8_nibble_hi = dest_u8 & 0b1111'0000 >> 4;
|
dest_map->reg->bytes[dest_map->byte] -= S86_CAST(uint8_t)opcode.immediate;
|
||||||
uint8_t new_dest_u8_nibble_lo = new_dest_u8 & 0b0000'1111 >> 0;
|
} else {
|
||||||
uint8_t new_dest_u8_nibble_hi = new_dest_u8 & 0b1111'0000 >> 4;
|
S86_ASSERT(opcode.immediate < S86_CAST(uint16_t)-1);
|
||||||
register_file.flags.auxiliary_carry = subtract ? new_dest_u8_nibble_hi > dest_u8_nibble_hi
|
dest_map->reg->word -= S86_CAST(uint16_t)opcode.immediate;
|
||||||
: new_dest_u8_nibble_lo < dest_u8_nibble_lo;
|
}
|
||||||
|
|
||||||
// NOTE: Sign check
|
|
||||||
register_file.flags.sign = new_dest_u8 & 0b1000'0000;
|
|
||||||
|
|
||||||
// NOTE: Update the register
|
|
||||||
dest.bytes[dest_map->byte] = new_dest_u8;
|
|
||||||
} else {
|
} else {
|
||||||
if (subtract)
|
S86_MnemonicOpToRegisterFileMap const *src_map = NULL;
|
||||||
src = ~src + 1;
|
for (size_t index = 0; !src_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) {
|
||||||
|
S86_MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index;
|
||||||
|
if (item->mnemonic_op == opcode.src)
|
||||||
|
src_map = item;
|
||||||
|
}
|
||||||
|
|
||||||
S86_Register16 new_dest = {0};
|
if (byte_op)
|
||||||
new_dest.word = dest.word + src;
|
dest_map->reg->bytes[dest_map->byte] -= src_map->reg->bytes[src_map->byte];
|
||||||
|
else
|
||||||
// NOTE: Overflow check
|
dest_map->reg->word -= src_map->reg->word;
|
||||||
bool initially_matching_sign_masks = (dest.word & sign_mask16) == (src & sign_mask16);
|
|
||||||
bool sign_masks_changed = (dest.word & sign_mask16) != (new_dest.word & sign_mask16);
|
|
||||||
register_file.flags.overflow = initially_matching_sign_masks && sign_masks_changed;
|
|
||||||
|
|
||||||
// NOTE: Auxiliary carry check
|
|
||||||
uint8_t dest_lo_nibble_lo = dest.bytes[S86_RegisterByte_Lo] & 0b0000'1111 >> 0;
|
|
||||||
uint8_t dest_lo_nibble_hi = dest.bytes[S86_RegisterByte_Lo] & 0b1111'0000 >> 4;
|
|
||||||
uint8_t new_dest_lo_nibble_lo = new_dest.bytes[S86_RegisterByte_Lo] & 0b0000'1111 >> 0;
|
|
||||||
uint8_t new_dest_lo_nibble_hi = new_dest.bytes[S86_RegisterByte_Lo] & 0b1111'0000 >> 4;
|
|
||||||
register_file.flags.auxiliary_carry = subtract ? new_dest_lo_nibble_hi > dest_lo_nibble_hi
|
|
||||||
: new_dest_lo_nibble_lo < dest_lo_nibble_lo;
|
|
||||||
|
|
||||||
// NOTE: Carry check
|
|
||||||
register_file.flags.carry = subtract ? new_dest.word > dest.word : new_dest.word < dest.word;
|
|
||||||
|
|
||||||
// NOTE: Sign check
|
|
||||||
register_file.flags.sign = new_dest.word & 0b1000'0000'0000'0000;
|
|
||||||
|
|
||||||
// NOTE: Update the register
|
|
||||||
dest.word = new_dest.word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lo_bit_count = _mm_popcnt_u32(S86_CAST(uint32_t)dest.bytes[S86_RegisterByte_Lo]);
|
S86_Str8 dest_reg16 = S86_MnemonicOpStr8(dest_map->mnemonic_op_reg16);
|
||||||
register_file.flags.parity = lo_bit_count % 2 == 0;
|
|
||||||
register_file.flags.zero = false;
|
|
||||||
if (opcode.mnemonic == S86_Mnemonic_ADD || opcode.mnemonic == S86_Mnemonic_SUB)
|
|
||||||
register_file.flags.zero = byte_op ? dest.bytes[dest_map->byte] == 0 : dest.word == 0;
|
|
||||||
|
|
||||||
if (opcode.mnemonic == S86_Mnemonic_CMP) {
|
register_file.zero_flag = byte_op ? dest_map->reg->bytes[dest_map->byte] == 0 : dest_map->reg->word == 0;
|
||||||
S86_PrintFmt(" ; ");
|
register_file.sign_flag = dest_map->reg->word & (byte_op ? 0b0000'0000'1000'0000 : 0b1000'0000'0000'0000);
|
||||||
|
S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(dest_reg16), prev_dest, dest_map->reg->word);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case S86_Mnemonic_CMP: {
|
||||||
|
S86_MnemonicOpToRegisterFileMap const *dest_map = NULL;
|
||||||
|
for (size_t index = 0; !dest_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) {
|
||||||
|
S86_MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index;
|
||||||
|
if (item->mnemonic_op == opcode.dest)
|
||||||
|
dest_map = item;
|
||||||
|
}
|
||||||
|
S86_ASSERT(dest_map);
|
||||||
|
|
||||||
|
S86_Register16 dest_copy = *dest_map->reg;
|
||||||
|
S86_Register16 *dest = &dest_copy;
|
||||||
|
|
||||||
|
bool byte_op = opcode.dest >= S86_MnemonicOp_AL && opcode.dest <= S86_MnemonicOp_BH;
|
||||||
|
if (opcode.src == S86_MnemonicOp_Immediate) {
|
||||||
|
if (byte_op) {
|
||||||
|
S86_ASSERT(opcode.immediate < S86_CAST(uint8_t)-1);
|
||||||
|
dest->bytes[dest_map->byte] -= S86_CAST(uint8_t)opcode.immediate;
|
||||||
|
} else {
|
||||||
|
S86_ASSERT(opcode.immediate < S86_CAST(uint16_t)-1);
|
||||||
|
dest->word -= S86_CAST(uint16_t)opcode.immediate;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
S86_Str8 dest_reg16 = S86_MnemonicOpStr8(dest_map->mnemonic_op_reg16);
|
S86_MnemonicOpToRegisterFileMap const *src_map = NULL;
|
||||||
S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(dest_reg16), prev_dest.word, dest.word);
|
for (size_t index = 0; !src_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) {
|
||||||
*dest_map->reg = dest;
|
S86_MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index;
|
||||||
|
if (item->mnemonic_op == opcode.src)
|
||||||
|
src_map = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte_op)
|
||||||
|
dest->bytes[dest_map->byte] -= src_map->reg->bytes[src_map->byte];
|
||||||
|
else
|
||||||
|
dest->word -= src_map->reg->word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register_file.sign_flag = dest_map->reg->word & (byte_op ? 0b0000'0000'1000'0000 : 0b1000'0000'0000'0000);
|
||||||
|
S86_PrintFmt(" ; ");
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!S86_RegisterFileFlagsEq(register_file.flags, prev_flags)) {
|
if (register_file.sign_flag != prev_sign_flag) {
|
||||||
S86_PrintFmt("flags:");
|
if (register_file.sign_flag) {
|
||||||
if (prev_flags.carry)
|
S86_PrintFmt("flags:->S ");
|
||||||
S86_PrintFmt("C");
|
} else {
|
||||||
if (prev_flags.parity)
|
S86_PrintFmt("flags:S-> ");
|
||||||
S86_PrintFmt("P");
|
}
|
||||||
if (prev_flags.auxiliary_carry)
|
}
|
||||||
S86_PrintFmt("A");
|
|
||||||
if (prev_flags.zero)
|
|
||||||
S86_PrintFmt("Z");
|
|
||||||
if (prev_flags.sign)
|
|
||||||
S86_PrintFmt("S");
|
|
||||||
if (prev_flags.overflow)
|
|
||||||
S86_PrintFmt("O");
|
|
||||||
|
|
||||||
S86_PrintFmt("->");
|
if (register_file.zero_flag != prev_zero_flag) {
|
||||||
if (register_file.flags.carry)
|
if (register_file.zero_flag) {
|
||||||
S86_PrintFmt("C");
|
S86_PrintFmt("flags:->PZ ");
|
||||||
if (register_file.flags.parity)
|
} else {
|
||||||
S86_PrintFmt("P");
|
S86_PrintFmt("flags:PZ-> ");
|
||||||
if (register_file.flags.auxiliary_carry)
|
}
|
||||||
S86_PrintFmt("A");
|
|
||||||
if (register_file.flags.zero)
|
|
||||||
S86_PrintFmt("Z");
|
|
||||||
if (register_file.flags.sign)
|
|
||||||
S86_PrintFmt("S");
|
|
||||||
if (register_file.flags.overflow)
|
|
||||||
S86_PrintFmt("O");
|
|
||||||
S86_PrintFmt(" ");
|
|
||||||
}
|
}
|
||||||
S86_Print(S86_STR8("\n"));
|
S86_Print(S86_STR8("\n"));
|
||||||
}
|
}
|
||||||
@ -1543,22 +1490,12 @@ int main(int argc, char **argv)
|
|||||||
S86_PrintLnFmt(" ss: 0x%04x (%u)", register_file.ss, register_file.ss);
|
S86_PrintLnFmt(" ss: 0x%04x (%u)", register_file.ss, register_file.ss);
|
||||||
if (register_file.ds.word)
|
if (register_file.ds.word)
|
||||||
S86_PrintLnFmt(" ds: 0x%04x (%u)", register_file.ds, register_file.ds);
|
S86_PrintLnFmt(" ds: 0x%04x (%u)", register_file.ds, register_file.ds);
|
||||||
|
if (register_file.zero_flag || register_file.sign_flag) {
|
||||||
S86_RegisterFileFlags nil_flags = {0};
|
S86_PrintFmt(" flags:");
|
||||||
if (!S86_RegisterFileFlagsEq(register_file.flags, nil_flags)) {
|
if (register_file.zero_flag)
|
||||||
S86_PrintFmt(" flags: ");
|
S86_PrintFmt(" PZ");
|
||||||
if (register_file.flags.carry)
|
if (register_file.sign_flag)
|
||||||
S86_PrintFmt("C");
|
S86_PrintFmt(" S");
|
||||||
if (register_file.flags.parity)
|
|
||||||
S86_PrintFmt("P");
|
|
||||||
if (register_file.flags.auxiliary_carry)
|
|
||||||
S86_PrintFmt("A");
|
|
||||||
if (register_file.flags.zero)
|
|
||||||
S86_PrintFmt("Z");
|
|
||||||
if (register_file.flags.sign)
|
|
||||||
S86_PrintFmt("S");
|
|
||||||
if (register_file.flags.overflow)
|
|
||||||
S86_PrintFmt("O");
|
|
||||||
S86_Print(S86_STR8("\n"));
|
S86_Print(S86_STR8("\n"));
|
||||||
}
|
}
|
||||||
S86_Print(S86_STR8("\n"));
|
S86_Print(S86_STR8("\n"));
|
||||||
|
@ -333,7 +333,6 @@ typedef struct S86_Opcode {
|
|||||||
S86_MnemonicOp dest; ///< Destination op for the mnemonic
|
S86_MnemonicOp dest; ///< Destination op for the mnemonic
|
||||||
int32_t displacement; ///< Opcode has displacement/data/offset
|
int32_t displacement; ///< Opcode has displacement/data/offset
|
||||||
int32_t immediate; ///< Immediate value when src/dest op is an immediate
|
int32_t immediate; ///< Immediate value when src/dest op is an immediate
|
||||||
bool immediate_is_8bit; ///< Immediate was 8bit and sign extended
|
|
||||||
S86_MnemonicOp seg_reg_prefix; ///< Segment register that should prefix the upcoming instruction
|
S86_MnemonicOp seg_reg_prefix; ///< Segment register that should prefix the upcoming instruction
|
||||||
} S86_Opcode;
|
} S86_Opcode;
|
||||||
|
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
#define WIN32_MEAN_AND_LEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
// NOTE: Macros
|
// NOTE: Macros
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
#define S86_STRINGIFY2(token) #token
|
#define S86_STRINGIFY2(token) #token
|
||||||
|
BIN
project.rdbg
BIN
project.rdbg
Binary file not shown.
Loading…
Reference in New Issue
Block a user