From 8b8edbe09b5114b9d6e4219036383fcec398021b Mon Sep 17 00:00:00 2001 From: doyle Date: Wed, 29 Mar 2023 00:05:28 +1100 Subject: [PATCH] sim8086: Split into multiple files --- part1/sim8086.c | 431 +---------------------------------------- part1/sim8086.h | 187 ++++++++++++++++++ part1/sim8086_stdlib.c | 175 +++++++++++++++++ part1/sim8086_stdlib.h | 67 +++++++ 4 files changed, 432 insertions(+), 428 deletions(-) create mode 100644 part1/sim8086.h create mode 100644 part1/sim8086_stdlib.c create mode 100644 part1/sim8086_stdlib.h diff --git a/part1/sim8086.c b/part1/sim8086.c index 5c0094c..072a92e 100644 --- a/part1/sim8086.c +++ b/part1/sim8086.c @@ -1,435 +1,10 @@ -#define WIN32_MEAN_AND_LEAN -#define NOMINMAX -#include +#include "sim8086_stdlib.h" +#include "sim8086.h" -#include -#include -#include -#include - -// NOTE: Macros -// ============================================================================ -#define S86_STRINGIFY2(token) #token -#define S86_STRINGIFY(token) S86_STRINGIFY2(token) -#define S86_ASSERT(expr) \ - if (!(expr)) { \ - S86_PrintLnFmt("Assertion triggered [file=\"" __FILE__ ":" S86_STRINGIFY(__LINE__) "\", expr=\"" #expr "\"]"); \ - __debugbreak(); \ - } \ - -#define S86_ARRAY_UCOUNT(array) sizeof((array)) / sizeof((array)[0]) -#define S86_CAST(Type) (Type) - -// NOTE: Globals -// ============================================================================ -typedef struct S86_Globals { - HANDLE stdout_handle; - bool write_to_console; -} S86_Globals; - -S86_Globals s86_globals; - -// NOTE: Strings -// ============================================================================ -typedef struct S86_Str8 { - char *data; - size_t size; -} S86_Str8; - -#define S86_STR8(string) (S86_Str8){.data = (string), .size = S86_ARRAY_UCOUNT(string) - 1 } -#define S86_STR8_FMT(string) (int)((string).size), (string).data - -// NOTE: Buffer -// ============================================================================ -typedef struct S86_Buffer { - char *data; - size_t size; -} S86_Buffer; - -typedef struct S86_BufferIterator { - S86_Buffer buffer; - size_t index; -} S86_BufferIterator; - -bool S86_BufferIsValid(S86_Buffer buffer); -S86_BufferIterator S86_BufferIteratorInit(S86_Buffer buffer); -bool S86_BufferIteratorHasMoreBytes(S86_BufferIterator it); -uint8_t S86_BufferIteratorNextByte(S86_BufferIterator *it); - -// NOTE: File -// ============================================================================ -S86_Buffer S86_FileRead(char const *file_path); -void S86_FileFree(S86_Buffer buffer); - -// NOTE: Print -// ============================================================================ -void S86_PrintLn(S86_Str8 string); -void S86_PrintLnFmt(char const *fmt, ...); - -// NOTE: Sim8086 -// ============================================================================ -typedef enum S86_InstructionType { - S86_InstructionType_MOVRegOrMemToOrFromReg, - S86_InstructionType_MOVImmediateToRegOrMem, - S86_InstructionType_MOVImmediateToReg, - S86_InstructionType_MOVMemToAccum, - S86_InstructionType_MOVAccumToMem, - S86_InstructionType_MOVRegOrMemToSegReg, - S86_InstructionType_MOVSegRegToRegOrMem, - - S86_InstructionType_PUSHRegOrMem, - S86_InstructionType_PUSHReg, - S86_InstructionType_PUSHSegReg, - - S86_InstructionType_POPRegOrMem, - S86_InstructionType_POPReg, - S86_InstructionType_POPSegReg, - - S86_InstructionType_XCHGRegOrMemWithReg, - S86_InstructionType_XCHGRegWithAccum, - - S86_InstructionType_INFixedPort, - S86_InstructionType_INVariablePort, - - S86_InstructionType_OUTFixedPort, - S86_InstructionType_OUTVariablePort, - - S86_InstructionType_XLAT, - - S86_InstructionType_LEA, - S86_InstructionType_LDS, - S86_InstructionType_LES, - S86_InstructionType_LAHF, - S86_InstructionType_SAHF, - S86_InstructionType_PUSHF, - S86_InstructionType_POPF, - - S86_InstructionType_ADDRegOrMemToOrFromReg, - S86_InstructionType_ADDImmediateToRegOrMem, - S86_InstructionType_ADDImmediateToAccum, - - S86_InstructionType_ADCRegOrMemWithRegToEither, - S86_InstructionType_ADCImmediateToRegOrMem, - S86_InstructionType_ADCImmediateToAccum, - - S86_InstructionType_INCRegOrMem, - S86_InstructionType_INCReg, - - S86_InstructionType_AAA, - S86_InstructionType_DAA, - - S86_InstructionType_SUBRegOrMemToOrFromReg, - S86_InstructionType_SUBImmediateFromRegOrMem, - S86_InstructionType_SUBImmediateFromAccum, - - S86_InstructionType_SBBRegOrMemAndRegToEither, - S86_InstructionType_SBBImmediateFromRegOrMem, - S86_InstructionType_SBBImmediateFromAccum, - - S86_InstructionType_DECRegOrMem, - S86_InstructionType_DECReg, - S86_InstructionType_NEG, - - S86_InstructionType_CMPRegOrMemAndReg, - S86_InstructionType_CMPImmediateWithRegOrMem, - S86_InstructionType_CMPImmediateWithAccum, - - S86_InstructionType_AAS, - S86_InstructionType_DAS, - - S86_InstructionType_MUL, - S86_InstructionType_IMUL, - S86_InstructionType_AAM, - S86_InstructionType_DIV, - S86_InstructionType_IDIV, - S86_InstructionType_AAD, - S86_InstructionType_CBW, - S86_InstructionType_CWD, - - S86_InstructionType_NOT, - S86_InstructionType_SHL_SAL, - S86_InstructionType_SHR, - S86_InstructionType_SAR, - S86_InstructionType_ROL, - S86_InstructionType_ROR, - S86_InstructionType_RCL, - S86_InstructionType_RCR, - - S86_InstructionType_ANDRegWithMemToEither, - S86_InstructionType_ANDImmediateToRegOrMem, - S86_InstructionType_ANDImmediateToAccum, - - S86_InstructionType_TESTRegOrMemAndReg, - S86_InstructionType_TESTImmediateAndRegOrMem, - S86_InstructionType_TESTImmediateAndAccum, - - S86_InstructionType_ORRegOrMemAndRegToEither, - S86_InstructionType_ORImmediateToRegOrMem, - S86_InstructionType_ORImmediateToAccum, - - S86_InstructionType_XORRegOrMemAndRegToEither, - S86_InstructionType_XORImmediateToRegOrMem, - S86_InstructionType_XORImmediateToAccum, - - S86_InstructionType_REP, - - S86_InstructionType_CALLDirectWithinSeg, - S86_InstructionType_CALLIndirectWithinSeg, - S86_InstructionType_CALLDirectInterSeg, - S86_InstructionType_CALLIndirectInterSeg, - - S86_InstructionType_JMPDirectWithinSeg, - S86_InstructionType_JMPDirectWithinSegShort, - S86_InstructionType_JMPIndirectWithinSeg, - S86_InstructionType_JMPDirectInterSeg, - S86_InstructionType_JMPIndirectInterSeg, - - S86_InstructionType_RETWithinSeg, - S86_InstructionType_RETWithinSegAddImmediateToSP, - S86_InstructionType_RETInterSeg, - S86_InstructionType_RETInterSegAddImmediateToSP, - - S86_InstructionType_JE_JZ, - S86_InstructionType_JL_JNGE, - S86_InstructionType_JLE_JNG, - S86_InstructionType_JB_JNAE, - S86_InstructionType_JBE_JNA, - S86_InstructionType_JP_JPE, - S86_InstructionType_JO, - S86_InstructionType_JS, - S86_InstructionType_JNE_JNZ, - S86_InstructionType_JNL_JGE, - S86_InstructionType_JNLE_JG, - S86_InstructionType_JNB_JAE, - S86_InstructionType_JNBE_JA, - S86_InstructionType_JNP_JO, - S86_InstructionType_JNO, - S86_InstructionType_JNS, - S86_InstructionType_LOOP, - S86_InstructionType_LOOPZ_LOOPE, - S86_InstructionType_LOOPNZ_LOOPNE, - S86_InstructionType_JCXZ, - - S86_InstructionType_INT, - S86_InstructionType_INT3, - S86_InstructionType_INTO, - S86_InstructionType_IRET, - - S86_InstructionType_CLC, - S86_InstructionType_CMC, - S86_InstructionType_STC, - S86_InstructionType_CLD, - S86_InstructionType_STD, - S86_InstructionType_CLI, - S86_InstructionType_STI, - S86_InstructionType_HLT, - S86_InstructionType_WAIT, - - S86_InstructionType_LOCK, - S86_InstructionType_SEGMENT, - - S86_InstructionType_Count, -} S86_InstructionType; - -/// Bit patterns and masks for decoding 8086 assembly. 8086 opcodes can be up -/// to 2 bytes long and mixed with instruction specific control bits. These -/// masks isolate the opcode bits from the bits can be checked after masking -/// the binary instruction stream. -/// -/// Instructions that do not have opcode bits in the 2nd byte will have the mask -/// set to 0. -typedef struct S86_Instruction { - uint8_t op_mask0; - uint8_t op_bits0; - uint8_t op_mask1; - uint8_t op_bits1; - S86_Str8 mnemonic; -} S86_Instruction; - -typedef struct S86_EffectiveAddressStr8 { - char data[32]; - size_t size; - bool has_displacement; -} S86_EffectiveAddressStr8; - -S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, uint8_t rm, uint8_t mod, uint8_t w, S86_Str8 seg_reg); +#include "sim8086_stdlib.c" // NOTE: Implementation // ============================================================================ -bool S86_BufferIsValid(S86_Buffer buffer) -{ - bool result = buffer.data && buffer.size; - return result; -} - -S86_BufferIterator S86_BufferIteratorInit(S86_Buffer buffer) -{ - S86_BufferIterator result = {0}; - result.buffer = buffer; - return result; -} - -bool S86_BufferIteratorHasMoreBytes(S86_BufferIterator it) -{ - bool result = S86_BufferIsValid(it.buffer) && it.index < it.buffer.size; - return result; -} - -uint8_t S86_BufferIteratorPeekByte(S86_BufferIterator *it) -{ - S86_ASSERT(it); - S86_ASSERT(S86_BufferIsValid(it->buffer)); - S86_ASSERT(it->index < it->buffer.size); - uint8_t result = it->buffer.data[it->index]; - return result; -} - -uint8_t S86_BufferIteratorNextByte(S86_BufferIterator *it) -{ - uint8_t result = S86_BufferIteratorPeekByte(it); - it->index++; - return result; -} - -S86_Buffer S86_FileRead(char const *file_path) -{ - S86_Buffer result = {0}; - - // NOTE: Determine file size - // ========================================================================= - WIN32_FILE_ATTRIBUTE_DATA file_attrib_data = {0}; - if (GetFileAttributesEx(file_path, GetFileExInfoStandard, &file_attrib_data) == 0) - return result; - - // NOTE: Open file - // ========================================================================= - HANDLE file_handle = CreateFile( - /*LPCSTR lpFileName*/ file_path, - /*DWORD dwDesiredAccess*/ GENERIC_READ, - /*DWORD dwShareMode*/ 0, - /*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ NULL, - /*DWORD dwCreationDisposition*/ OPEN_EXISTING, - /*DWORD dwFlagsAndAttributes*/ 0, - /*HANDLE hTemplateFile*/ NULL - ); - - if (file_handle == INVALID_HANDLE_VALUE) - return result; - - // NOTE: Allocate buffer - // ========================================================================= - uint64_t file_size = (uint64_t)file_attrib_data.nFileSizeHigh << 32 | (uint64_t)file_attrib_data.nFileSizeLow << 0; - S86_ASSERT(file_size < (DWORD)-1); - char *buffer = VirtualAlloc( - /*LPVOID lpAddress*/ NULL, - /*SIZE_T dwSize*/ file_size, - /*DWORD flAllocationType*/ MEM_COMMIT | MEM_RESERVE, - /*DWORD flProtect*/ PAGE_READWRITE - ); - - if (!buffer) - goto end; - - // NOTE: Read file to buffer - // ========================================================================= - DWORD bytes_read = 0; - BOOL read_file_result = ReadFile( - /*HANDLE hFile*/ file_handle, - /*LPVOID lpBuffer*/ buffer, - /*DWORD nNumberOfBytesToRead*/ S86_CAST(DWORD)file_size, - /*LPDWORD lpNumberOfBytesRead*/ &bytes_read, - /*LPOVERLAPPED lpOverlapped*/ NULL - ); - - // NOTE: Handle read result - // ========================================================================= - if (read_file_result == 0) { - VirtualFree(buffer, 0, MEM_RELEASE); - } else { - result.data = buffer; - result.size = file_size; - } - -end: - CloseHandle(file_handle); - return result; -}; - -void S86_FileFree(S86_Buffer buffer) -{ - if (S86_BufferIsValid(buffer)) - VirtualFree(buffer.data, 0, MEM_RELEASE); -} - -void S86_Print(S86_Str8 string) -{ - if (s86_globals.stdout_handle == NULL) { - s86_globals.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD mode = 0; - BOOL get_console_mode_result = GetConsoleMode( - /*HANDLE hConsoleHandle*/ s86_globals.stdout_handle, - /*LPDWORD lpMode*/ &mode - ); - s86_globals.write_to_console = get_console_mode_result != 0; - } - - - S86_ASSERT(string.size < S86_CAST(DWORD)-1); - if (s86_globals.write_to_console) { - DWORD chars_written = 0; - WriteConsoleA(s86_globals.stdout_handle, string.data, (DWORD)string.size, &chars_written, NULL); - } else { - DWORD bytes_written = 0; - WriteFile(s86_globals.stdout_handle, string.data, (DWORD)string.size, &bytes_written, NULL); - } -} - -void S86_PrintFmt(char const *fmt, ...) -{ - va_list args, args_copy; - va_start(args, fmt); - - va_copy(args_copy, args); - int string_size = vsnprintf(NULL, 0, fmt, args_copy); - va_end(args_copy); - - char buffer[8192]; - S86_ASSERT(string_size >= 0 && string_size < S86_ARRAY_UCOUNT(buffer)); - if (string_size) { - vsnprintf(buffer, sizeof(buffer), fmt, args); - S86_Str8 string = {.data = buffer, .size = string_size}; - S86_Print(string); - } - - va_end(args); -} - -void S86_PrintLn(S86_Str8 string) -{ - S86_Print(string); - S86_Print(S86_STR8("\n")); -} - -void S86_PrintLnFmt(char const *fmt, ...) -{ - va_list args, args_copy; - va_start(args, fmt); - - va_copy(args_copy, args); - int string_size = vsnprintf(NULL, 0, fmt, args_copy); - va_end(args_copy); - - char buffer[8192]; - S86_ASSERT(string_size >= 0 && string_size < S86_ARRAY_UCOUNT(buffer)); - if (string_size) { - vsnprintf(buffer, sizeof(buffer), fmt, args); - S86_Str8 string = {.data = buffer, .size = string_size}; - S86_PrintLn(string); - } - - va_end(args); -} - S86_Str8 REGISTER_FIELD_ENCODING[2][8]; S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, uint8_t rm, uint8_t mod, uint8_t w, S86_Str8 seg_reg) { diff --git a/part1/sim8086.h b/part1/sim8086.h new file mode 100644 index 0000000..08c08bd --- /dev/null +++ b/part1/sim8086.h @@ -0,0 +1,187 @@ +// NOTE: Sim8086 +// ============================================================================ +typedef enum S86_InstructionType { + S86_InstructionType_MOVRegOrMemToOrFromReg, + S86_InstructionType_MOVImmediateToRegOrMem, + S86_InstructionType_MOVImmediateToReg, + S86_InstructionType_MOVMemToAccum, + S86_InstructionType_MOVAccumToMem, + S86_InstructionType_MOVRegOrMemToSegReg, + S86_InstructionType_MOVSegRegToRegOrMem, + + S86_InstructionType_PUSHRegOrMem, + S86_InstructionType_PUSHReg, + S86_InstructionType_PUSHSegReg, + + S86_InstructionType_POPRegOrMem, + S86_InstructionType_POPReg, + S86_InstructionType_POPSegReg, + + S86_InstructionType_XCHGRegOrMemWithReg, + S86_InstructionType_XCHGRegWithAccum, + + S86_InstructionType_INFixedPort, + S86_InstructionType_INVariablePort, + + S86_InstructionType_OUTFixedPort, + S86_InstructionType_OUTVariablePort, + + S86_InstructionType_XLAT, + + S86_InstructionType_LEA, + S86_InstructionType_LDS, + S86_InstructionType_LES, + S86_InstructionType_LAHF, + S86_InstructionType_SAHF, + S86_InstructionType_PUSHF, + S86_InstructionType_POPF, + + S86_InstructionType_ADDRegOrMemToOrFromReg, + S86_InstructionType_ADDImmediateToRegOrMem, + S86_InstructionType_ADDImmediateToAccum, + + S86_InstructionType_ADCRegOrMemWithRegToEither, + S86_InstructionType_ADCImmediateToRegOrMem, + S86_InstructionType_ADCImmediateToAccum, + + S86_InstructionType_INCRegOrMem, + S86_InstructionType_INCReg, + + S86_InstructionType_AAA, + S86_InstructionType_DAA, + + S86_InstructionType_SUBRegOrMemToOrFromReg, + S86_InstructionType_SUBImmediateFromRegOrMem, + S86_InstructionType_SUBImmediateFromAccum, + + S86_InstructionType_SBBRegOrMemAndRegToEither, + S86_InstructionType_SBBImmediateFromRegOrMem, + S86_InstructionType_SBBImmediateFromAccum, + + S86_InstructionType_DECRegOrMem, + S86_InstructionType_DECReg, + S86_InstructionType_NEG, + + S86_InstructionType_CMPRegOrMemAndReg, + S86_InstructionType_CMPImmediateWithRegOrMem, + S86_InstructionType_CMPImmediateWithAccum, + + S86_InstructionType_AAS, + S86_InstructionType_DAS, + + S86_InstructionType_MUL, + S86_InstructionType_IMUL, + S86_InstructionType_AAM, + S86_InstructionType_DIV, + S86_InstructionType_IDIV, + S86_InstructionType_AAD, + S86_InstructionType_CBW, + S86_InstructionType_CWD, + + S86_InstructionType_NOT, + S86_InstructionType_SHL_SAL, + S86_InstructionType_SHR, + S86_InstructionType_SAR, + S86_InstructionType_ROL, + S86_InstructionType_ROR, + S86_InstructionType_RCL, + S86_InstructionType_RCR, + + S86_InstructionType_ANDRegWithMemToEither, + S86_InstructionType_ANDImmediateToRegOrMem, + S86_InstructionType_ANDImmediateToAccum, + + S86_InstructionType_TESTRegOrMemAndReg, + S86_InstructionType_TESTImmediateAndRegOrMem, + S86_InstructionType_TESTImmediateAndAccum, + + S86_InstructionType_ORRegOrMemAndRegToEither, + S86_InstructionType_ORImmediateToRegOrMem, + S86_InstructionType_ORImmediateToAccum, + + S86_InstructionType_XORRegOrMemAndRegToEither, + S86_InstructionType_XORImmediateToRegOrMem, + S86_InstructionType_XORImmediateToAccum, + + S86_InstructionType_REP, + + S86_InstructionType_CALLDirectWithinSeg, + S86_InstructionType_CALLIndirectWithinSeg, + S86_InstructionType_CALLDirectInterSeg, + S86_InstructionType_CALLIndirectInterSeg, + + S86_InstructionType_JMPDirectWithinSeg, + S86_InstructionType_JMPDirectWithinSegShort, + S86_InstructionType_JMPIndirectWithinSeg, + S86_InstructionType_JMPDirectInterSeg, + S86_InstructionType_JMPIndirectInterSeg, + + S86_InstructionType_RETWithinSeg, + S86_InstructionType_RETWithinSegAddImmediateToSP, + S86_InstructionType_RETInterSeg, + S86_InstructionType_RETInterSegAddImmediateToSP, + + S86_InstructionType_JE_JZ, + S86_InstructionType_JL_JNGE, + S86_InstructionType_JLE_JNG, + S86_InstructionType_JB_JNAE, + S86_InstructionType_JBE_JNA, + S86_InstructionType_JP_JPE, + S86_InstructionType_JO, + S86_InstructionType_JS, + S86_InstructionType_JNE_JNZ, + S86_InstructionType_JNL_JGE, + S86_InstructionType_JNLE_JG, + S86_InstructionType_JNB_JAE, + S86_InstructionType_JNBE_JA, + S86_InstructionType_JNP_JO, + S86_InstructionType_JNO, + S86_InstructionType_JNS, + S86_InstructionType_LOOP, + S86_InstructionType_LOOPZ_LOOPE, + S86_InstructionType_LOOPNZ_LOOPNE, + S86_InstructionType_JCXZ, + + S86_InstructionType_INT, + S86_InstructionType_INT3, + S86_InstructionType_INTO, + S86_InstructionType_IRET, + + S86_InstructionType_CLC, + S86_InstructionType_CMC, + S86_InstructionType_STC, + S86_InstructionType_CLD, + S86_InstructionType_STD, + S86_InstructionType_CLI, + S86_InstructionType_STI, + S86_InstructionType_HLT, + S86_InstructionType_WAIT, + + S86_InstructionType_LOCK, + S86_InstructionType_SEGMENT, + + S86_InstructionType_Count, +} S86_InstructionType; + +/// Bit patterns and masks for decoding 8086 assembly. 8086 opcodes can be up +/// to 2 bytes long and mixed with instruction specific control bits. These +/// masks isolate the opcode bits from the bits can be checked after masking +/// the binary instruction stream. +/// +/// Instructions that do not have opcode bits in the 2nd byte will have the mask +/// set to 0. +typedef struct S86_Instruction { + uint8_t op_mask0; + uint8_t op_bits0; + uint8_t op_mask1; + uint8_t op_bits1; + S86_Str8 mnemonic; +} S86_Instruction; + +typedef struct S86_EffectiveAddressStr8 { + char data[32]; + size_t size; + bool has_displacement; +} S86_EffectiveAddressStr8; + +S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, uint8_t rm, uint8_t mod, uint8_t w, S86_Str8 seg_reg); diff --git a/part1/sim8086_stdlib.c b/part1/sim8086_stdlib.c new file mode 100644 index 0000000..d793cd7 --- /dev/null +++ b/part1/sim8086_stdlib.c @@ -0,0 +1,175 @@ +// NOTE: Implementation +// ============================================================================ +bool S86_BufferIsValid(S86_Buffer buffer) +{ + bool result = buffer.data && buffer.size; + return result; +} + +S86_BufferIterator S86_BufferIteratorInit(S86_Buffer buffer) +{ + S86_BufferIterator result = {0}; + result.buffer = buffer; + return result; +} + +bool S86_BufferIteratorHasMoreBytes(S86_BufferIterator it) +{ + bool result = S86_BufferIsValid(it.buffer) && it.index < it.buffer.size; + return result; +} + +uint8_t S86_BufferIteratorPeekByte(S86_BufferIterator *it) +{ + S86_ASSERT(it); + S86_ASSERT(S86_BufferIsValid(it->buffer)); + S86_ASSERT(it->index < it->buffer.size); + uint8_t result = it->buffer.data[it->index]; + return result; +} + +uint8_t S86_BufferIteratorNextByte(S86_BufferIterator *it) +{ + uint8_t result = S86_BufferIteratorPeekByte(it); + it->index++; + return result; +} + +S86_Buffer S86_FileRead(char const *file_path) +{ + S86_Buffer result = {0}; + + // NOTE: Determine file size + // ========================================================================= + WIN32_FILE_ATTRIBUTE_DATA file_attrib_data = {0}; + if (GetFileAttributesEx(file_path, GetFileExInfoStandard, &file_attrib_data) == 0) + return result; + + // NOTE: Open file + // ========================================================================= + HANDLE file_handle = CreateFile( + /*LPCSTR lpFileName*/ file_path, + /*DWORD dwDesiredAccess*/ GENERIC_READ, + /*DWORD dwShareMode*/ 0, + /*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ NULL, + /*DWORD dwCreationDisposition*/ OPEN_EXISTING, + /*DWORD dwFlagsAndAttributes*/ 0, + /*HANDLE hTemplateFile*/ NULL + ); + + if (file_handle == INVALID_HANDLE_VALUE) + return result; + + // NOTE: Allocate buffer + // ========================================================================= + uint64_t file_size = (uint64_t)file_attrib_data.nFileSizeHigh << 32 | (uint64_t)file_attrib_data.nFileSizeLow << 0; + S86_ASSERT(file_size < (DWORD)-1); + char *buffer = VirtualAlloc( + /*LPVOID lpAddress*/ NULL, + /*SIZE_T dwSize*/ file_size, + /*DWORD flAllocationType*/ MEM_COMMIT | MEM_RESERVE, + /*DWORD flProtect*/ PAGE_READWRITE + ); + + if (!buffer) + goto end; + + // NOTE: Read file to buffer + // ========================================================================= + DWORD bytes_read = 0; + BOOL read_file_result = ReadFile( + /*HANDLE hFile*/ file_handle, + /*LPVOID lpBuffer*/ buffer, + /*DWORD nNumberOfBytesToRead*/ S86_CAST(DWORD)file_size, + /*LPDWORD lpNumberOfBytesRead*/ &bytes_read, + /*LPOVERLAPPED lpOverlapped*/ NULL + ); + + // NOTE: Handle read result + // ========================================================================= + if (read_file_result == 0) { + VirtualFree(buffer, 0, MEM_RELEASE); + } else { + result.data = buffer; + result.size = file_size; + } + +end: + CloseHandle(file_handle); + return result; +}; + +void S86_FileFree(S86_Buffer buffer) +{ + if (S86_BufferIsValid(buffer)) + VirtualFree(buffer.data, 0, MEM_RELEASE); +} + +void S86_Print(S86_Str8 string) +{ + if (s86_globals.stdout_handle == NULL) { + s86_globals.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD mode = 0; + BOOL get_console_mode_result = GetConsoleMode( + /*HANDLE hConsoleHandle*/ s86_globals.stdout_handle, + /*LPDWORD lpMode*/ &mode + ); + s86_globals.write_to_console = get_console_mode_result != 0; + } + + + S86_ASSERT(string.size < S86_CAST(DWORD)-1); + if (s86_globals.write_to_console) { + DWORD chars_written = 0; + WriteConsoleA(s86_globals.stdout_handle, string.data, (DWORD)string.size, &chars_written, NULL); + } else { + DWORD bytes_written = 0; + WriteFile(s86_globals.stdout_handle, string.data, (DWORD)string.size, &bytes_written, NULL); + } +} + +void S86_PrintFmt(char const *fmt, ...) +{ + va_list args, args_copy; + va_start(args, fmt); + + va_copy(args_copy, args); + int string_size = vsnprintf(NULL, 0, fmt, args_copy); + va_end(args_copy); + + char buffer[8192]; + S86_ASSERT(string_size >= 0 && string_size < S86_ARRAY_UCOUNT(buffer)); + if (string_size) { + vsnprintf(buffer, sizeof(buffer), fmt, args); + S86_Str8 string = {.data = buffer, .size = string_size}; + S86_Print(string); + } + + va_end(args); +} + +void S86_PrintLn(S86_Str8 string) +{ + S86_Print(string); + S86_Print(S86_STR8("\n")); +} + +void S86_PrintLnFmt(char const *fmt, ...) +{ + va_list args, args_copy; + va_start(args, fmt); + + va_copy(args_copy, args); + int string_size = vsnprintf(NULL, 0, fmt, args_copy); + va_end(args_copy); + + char buffer[8192]; + S86_ASSERT(string_size >= 0 && string_size < S86_ARRAY_UCOUNT(buffer)); + if (string_size) { + vsnprintf(buffer, sizeof(buffer), fmt, args); + S86_Str8 string = {.data = buffer, .size = string_size}; + S86_PrintLn(string); + } + + va_end(args); +} diff --git a/part1/sim8086_stdlib.h b/part1/sim8086_stdlib.h new file mode 100644 index 0000000..deb2eed --- /dev/null +++ b/part1/sim8086_stdlib.h @@ -0,0 +1,67 @@ +#define WIN32_MEAN_AND_LEAN +#define NOMINMAX +#include + +#include +#include +#include +#include + +// NOTE: Macros +// ============================================================================ +#define S86_STRINGIFY2(token) #token +#define S86_STRINGIFY(token) S86_STRINGIFY2(token) +#define S86_ASSERT(expr) \ + if (!(expr)) { \ + S86_PrintLnFmt("Assertion triggered [file=\"" __FILE__ ":" S86_STRINGIFY(__LINE__) "\", expr=\"" #expr "\"]"); \ + __debugbreak(); \ + } \ + +#define S86_ARRAY_UCOUNT(array) sizeof((array)) / sizeof((array)[0]) +#define S86_CAST(Type) (Type) + +// NOTE: Globals +// ============================================================================ +typedef struct S86_Globals { + HANDLE stdout_handle; + bool write_to_console; +} S86_Globals; + +S86_Globals s86_globals; + +// NOTE: Strings +// ============================================================================ +typedef struct S86_Str8 { + char *data; + size_t size; +} S86_Str8; + +#define S86_STR8(string) (S86_Str8){.data = (string), .size = S86_ARRAY_UCOUNT(string) - 1 } +#define S86_STR8_FMT(string) (int)((string).size), (string).data + +// NOTE: Buffer +// ============================================================================ +typedef struct S86_Buffer { + char *data; + size_t size; +} S86_Buffer; + +typedef struct S86_BufferIterator { + S86_Buffer buffer; + size_t index; +} S86_BufferIterator; + +bool S86_BufferIsValid(S86_Buffer buffer); +S86_BufferIterator S86_BufferIteratorInit(S86_Buffer buffer); +bool S86_BufferIteratorHasMoreBytes(S86_BufferIterator it); +uint8_t S86_BufferIteratorNextByte(S86_BufferIterator *it); + +// NOTE: File +// ============================================================================ +S86_Buffer S86_FileRead(char const *file_path); +void S86_FileFree(S86_Buffer buffer); + +// NOTE: Print +// ============================================================================ +void S86_PrintLn(S86_Str8 string); +void S86_PrintLnFmt(char const *fmt, ...);