From 8b4c8a2c71de065f69de96c95b51e0a074a8b4c8 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 7 Aug 2026 01:06:57 -0400 Subject: [PATCH] got file reading working for the binary. --- .gitattributes | 3 + code/duffle/Readme.md | 10 ++ code/duffle/analysis.h | 4 + code/duffle/dsl.h | 117 +++++++++++++++---- code/duffle/encoding.h | 65 ++++++++++- code/duffle/files.h | 70 +++++++++++ code/duffle/math.h | 42 +++++++ code/duffle/memory.h | 20 +++- code/duffle/text.h | 30 ++++- code/duffle/win32.h | 257 ++++++++++++++++++++++++++++++++--------- code/part_1/sim_8086.c | 27 ++++- perfaware.proj | 2 +- scripts/build.ps1 | 13 ++- 13 files changed, 566 insertions(+), 94 deletions(-) create mode 100644 .gitattributes create mode 100644 code/duffle/files.h create mode 100644 code/duffle/math.h diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6444bd5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +code/8086/* linguist-language=C +code/duffle/* linguist-language=C +code/part_1/* linguist-language=C diff --git a/code/duffle/Readme.md b/code/duffle/Readme.md index 3980f27..f93fdaf 100644 --- a/code/duffle/Readme.md +++ b/code/duffle/Readme.md @@ -6,3 +6,13 @@ Sandbox: Windows 11 (for now) Compiler: clang Standard: c11 ``` + +Scrapped togther stuff from several repos and studies. + +Some of my favorite C code: + +```txt +stb +gb or zpl +raddebugger +``` diff --git a/code/duffle/analysis.h b/code/duffle/analysis.h index 143057d..57ca3f4 100644 --- a/code/duffle/analysis.h +++ b/code/duffle/analysis.h @@ -14,4 +14,8 @@ #else #define assert(cond) #endif + +#define trap() __builtin_trap() + +#define assert_always(x) do { if((x) == false) {trap();} } while(0) #pragma endregion Debug diff --git a/code/duffle/dsl.h b/code/duffle/dsl.h index 6c9b24e..1f7e091 100644 --- a/code/duffle/dsl.h +++ b/code/duffle/dsl.h @@ -9,6 +9,7 @@ Standard: c23 #pragma clang diagnostic ignored "-Wunused-variable" #pragma clang diagnostic ignored "-Wswitch" #pragma clang diagnostic ignored "-Wuninitialized" +#pragma clang diagnostic ignored "-Wmicrosoft-enum-forward-reference" // #pragma comment(lib, "Advapi32.lib") // #pragma comment(lib, "gdi32.lib") // #pragma comment(lib, "Kernel32.lib") @@ -16,8 +17,19 @@ Standard: c23 // #pragma comment(lib, "user32.lib") // #pragma comment(lib, "ucrt.lib") // #pragma comment(lib, "vcruntime.lib") + +#pragma region Platform +#define CLANG_OPTIMIZE_DISABLE _Pragma("clang optimize off") +#define CLANG_OPTIMIZE_ENABLE _Pragma("clang optimize on") + +#define DUFFLE_x86_64 1 +#define DUFFLE_WINDOWS 1 + #define WinAPI __attribute((__stdcall__)) __attribute__((__force_align_arg_pointer__)) // Win32 Syscall FFI +#define os_layer // Marker for interfaced resolved by os platform layer. +#pragma endregion Platform + #define offset_of(type, member) cast(U8,__builtin_offsetof(type,member)) #define static_assert _Static_assert #define typeof __typeof__ @@ -67,7 +79,7 @@ Standard: c23 #define EUB_ restrict // Execute Unit Bound: Data is siloed in the ALU Register File. The Load/Store Unit is bypassed. (Route to Execution Unit. Keep in registers) #define ISO_ restrict // Isolated Provenance: Alternative to Exu_. Guarantees electrical memory isolation, - // unlocking the compiler’s ability to safely pack data across multiple parallel SIMD lanes (vectorization). + // unlocking the compiler’s ability to safely pack data across multiple parallel SIMD lanes (vectorization). #define LSU_ volatile // Load/Store Unit Bound: The compiler is forbidden from caching in registers. Forces physical L1 Cache matrix sampling. #define LIVE_ volatile // Live External Data: Alternative to Lsu_ emphasizing the memory is tapped by an external electrical actor. @@ -107,7 +119,7 @@ Standard: c23 #define Array_expand(type,len) type Array_sym(type, len)[len]; typedef PtrSet_(Array_sym(type, len)) #define Array_(type,len) Array_expand(type,len) #define Bit_(id,b) id = (1 << b), tmpl(id,pos) = b -#define Enum_(underlying_type, symbol) underlying_type TSet_(symbol); enum symbol +#define Enum_(underlying_type, symbol) underlying_type TSet_(symbol); enum symbol #define Proc_(symbol) symbol #define Relative_(symbol) // Does nothing but annotate that a symbol is associated with another. #define Struct_(symbol) struct symbol TSet_(symbol); struct symbol @@ -206,14 +218,17 @@ def_signed_ops(le, <=) #define dbg_args(...) __VA_ARGS__ #pragma region Control Flow & Iteration +#define unreachable() __builtin_unreachable() + #define each_iter(type, iter, end) (type iter = 0; iter < end; ++ iter) #define index_iter(type, iter, begin, op, end) (type iter = begin; iter op end; (begin < end ? ++ iter : -- iter)) #define range_iter(iter,op,range) (T_((range).p0) iter = (range).p0; iter op (range).p1; ((range).p0 < (range).p1 ? ++ iter : -- iter)) -#define defer(expr) for(U4 once= 1; once!=1;++ once,(expr)) // Basic do something after body -#define scope(begin,end) for(U4 once=(1,(begin)); once!=1;++ once,(end )) // Do things before or after a scope -#define defer_rewind(cursor) for(T_(cursor) sp=cursor,once=0; once!=1;++ once,cursor=sp) // Used with arenas/stacks -#define defer_info(type,expr, ...) for(type info= {__VA_ARGS__}; info.once!=1;++info.once,(expr)) // Defer with tracked state +#define defer(expr) for(U4 once= 1; once!=1;++ once,(expr)) // Basic do something after body +#define defer_rewind(cursor) for(T_(cursor) sp=cursor,once=0; once!=1;++ once,cursor=sp) // Used with arenas/stacks +#define defer_info(type,expr, ...) for(type info={__VA_ARGS__}; info.once!=1;++info.once,(expr)) // Defer with tracked state +#define scope(begin,end) for(U4 once=(1,(begin)); once!=1;++ once,(end )) // Do things before or after a scope +#define scope_info(type,begin,end) for(type info=begin; info.once!=1;++info.once,(end )) #define do_while(cond) for (U4 once=0; once!=1 || (cond); ++once) @@ -225,35 +240,87 @@ def_signed_ops(le, <=) ++ iter.cursor \ ) #define Span_(type) \ - Struct_(tmpl( Span,type)) { type begin; type end; }; \ + Struct_(tmpl( Span,type)) { type begin; type end; }; \ typedef Struct_(tmpl(Iter_Span,type)) { tmpl(Span,type) r; type cursor; } #pragma endregion Control Flow & Iteration typedef Span_(S4); typedef Span_(U4); typedef Span_(U8); +#pragma region Thread Coherence +FI_ void barrier_compiler(void){asm volatile("::""memory");} // Compiler Barrier +FI_ void barrier_memory (void){__builtin_ia32_mfence();} // Memory Barrier +FI_ void barrier_read (void){__builtin_ia32_lfence();} // Read Barrier +FI_ void barrier_write (void){__builtin_ia32_sfence();} // Write Barrier -#pragma region Math -#define u8_max 0xffffffffffffffffull +// x86-64 +FI_ U4 atm_add_u4 (U4_R addr, U4 value){asm volatile("lock xaddl %0,%1":"=r"(value),"=m"(addr[0]):"0"(value),"m"(addr[0]):"memory","cc");return value;} +FI_ U8 atm_add_u8 (U8_R addr, U8 value){asm volatile("lock xaddq %0,%1":"=r"(value),"=m"(addr[0]):"0"(value),"m"(addr[0]):"memory","cc");return value;} +FI_ U4 atm_swap_u4(U4_R addr, U4 value){asm volatile("lock xchgl %0,%1":"=r"(value),"=m"(addr[0]):"0"(value),"m"(addr[0]):"memory","cc");return value;} +FI_ U8 atm_swap_u8(U8_R addr, U8 value){asm volatile("lock xchgq %0,%1":"=r"(value),"=m"(addr[0]):"0"(value),"m"(addr[0]):"memory","cc");return value;} +#pragma endregion Thread Coherence -#define min(A,B) (((A) < (B)) ? (A) : (B)) -#define max(A,B) (((A) > (B)) ? (A) : (B)) -#define clamp_bot(X,B) max(X, B) // Clamp "X" by "B" +#pragma region Misc +enum { + Bitmask_3 = 0x00000007, + Bitmask_4 = 0x0000000f, + Bitmask_5 = 0x0000001f, + Bitmask_6 = 0x0000003f, + Bitmask_10 = 0x000003ff, +}; -#define clamp_decrement(X) (((X) > 0) ? ((X) - 1) : 0) +typedef Enum_(U4, WeekDay) { + WeekDay_Sun, + WeekDay_Mon, + WeekDay_Tue, + WeekDay_Wed, + WeekDay_Thu, + WeekDay_Fri, + WeekDay_Sat, + WeekDay_Num, +}; -typedef Struct_(R1_U1){ U1 p0; U1 p1; }; -typedef Struct_(R1_U2){ U2 p0; U2 p1; }; -typedef Struct_(R1_U4){ U4 p0; U2 p4; }; -typedef Struct_(R1_U8){ U8 p0; U8 p4; }; +typedef Enum_(U4, Month) { + Month_Jan, + Month_Feb, + Month_Mar, + Month_Apr, + Month_May, + Month_Jun, + Month_Jul, + Month_Aug, + Month_Sep, + Month_Oct, + Month_Nov, + Month_Dec, + Month_Num, +}; -typedef Struct_(V2_U1){ U1 x; U1 y;}; +typedef U8 DenseTime; -FI_ B8 add_of (U8 a, U8 b, U8*R_ res) { return __builtin_uaddll_overflow(a, b, res); } -FI_ B8 sub_of (U8 a, U8 b, U8*R_ res) { return __builtin_usubll_overflow(a, b, res); } -FI_ B8 mul_of (U8 a, U8 b, U8*R_ res) { return __builtin_umulll_overflow(a, b, res); } -FI_ B8 add_s_of(S8 a, S8 b, S8*R_ res) { return __builtin_saddll_overflow(a, b, res); } -FI_ B8 sub_s_of(S8 a, S8 b, S8*R_ res) { return __builtin_ssubll_overflow(a, b, res); } -FI_ B8 mul_s_of(S8 a, S8 b, S8*R_ res) { return __builtin_smulll_overflow(a, b, res); } -#pragma endregion Math +typedef Struct_(DateTime) { + U4 micro_sec; // [0,999] + U4 msec; // [0,999] + U4 sec; // [0,60] + U4 min; // [0,59] + U4 hour; // [0,24] + U4 day; // [0,30] + WeekDay week_day; + Month month; + U4 year; // 1 = 1 CE, 0 = 1 BC +}; + +I_ DenseTime +dense_time_from_date_time(DateTime date_time) { + DenseTime result = 0; + result += date_time.year; result *= 12; + result += date_time.month; result *= 31; + result += date_time.day; result *= 24; + result += date_time.hour; result *= 60; + result += date_time.min; result *= 61; + result += date_time.sec; result *= 1000; + result += date_time.msec; + return(result); +} +#pragma endregion Misc diff --git a/code/duffle/encoding.h b/code/duffle/encoding.h index bdbaa94..5766b5d 100644 --- a/code/duffle/encoding.h +++ b/code/duffle/encoding.h @@ -3,9 +3,70 @@ # include "dsl.h" #endif -#pragma region Encoding +typedef struct UnicodeDecode UnicodeDecode; +struct UnicodeDecode { + U4 inc; + U4 codepoint; +}; + +RO_ global U1 utf8_class[32] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, }; + FI_ void u64_to_hex(U8 val, char* buf, S4 chars) { static const char hex_chars[] = "0123456789ABCDEF"; for(S1 i = chars - 1; i >= 0; --i) { buf[i] = hex_chars[val & 0xF]; val >>= 4; } } -#pragma endregion Encoding + +internal UnicodeDecode +utf8_decode(U1* str, U1 max) { + UnicodeDecode result = {1, Max_U4}; + U1 byte = str[0]; + U1 byte_class = utf8_class[byte >> 3]; + switch(byte_class) { + case 1: { result.codepoint = byte; } break; + case 2: if (1 < max) { + U1 cont_byte = str[1]; + if(utf8_class[cont_byte >> 3] == 0) { + result.codepoint = (byte & Bitmask_5) << 6; + result.codepoint |= (cont_byte & Bitmask_6); + result.inc = 2; + } + } break; + case 3: if(2 < max) { + U1 cont_byte[2] = {str[1], str[2]}; + if ( utf8_class[cont_byte[0] >> 3] == 0 + && utf8_class[cont_byte[1] >> 3] == 0) { + result.codepoint = (byte & Bitmask_4) << 12; + result.codepoint |= ((cont_byte[0] & Bitmask_6) << 6); + result.codepoint |= (cont_byte[1] & Bitmask_6); + result.inc = 3; + } + }break; + case 4: if(3 < max) { + U1 cont_byte[3] = {str[1], str[2], str[3]}; + if ( utf8_class[cont_byte[0] >> 3] == 0 + && utf8_class[cont_byte[1] >> 3] == 0 + && utf8_class[cont_byte[2] >> 3] == 0) { + result.codepoint = (byte & Bitmask_3) << 18; + result.codepoint |= ((cont_byte[0] & Bitmask_6) << 12); + result.codepoint |= ((cont_byte[1] & Bitmask_6) << 6); + result.codepoint |= (cont_byte[2] & Bitmask_6); + result.inc = 4; + } + } + } + return result; +} + +I_ U4 +utf16_encode(U2* str, U4 codepoint) { + U4 inc = 1; + if (codepoint == Max_U4) { str[0] = (U2)'?'; } + else if (codepoint < 0x10000) { str[0] = (U2)codepoint; } + else { + U4 v = codepoint - 0x10000; + str[0] = Csafe_u2u4(0xD800 + (v >> 10)); + str[1] = Csafe_u2u4(0xDC00 + (v & Bitmask_10)); + inc = 2; + } + return inc; +} diff --git a/code/duffle/files.h b/code/duffle/files.h new file mode 100644 index 0000000..d786cf8 --- /dev/null +++ b/code/duffle/files.h @@ -0,0 +1,70 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "dsl.h" +# include "memory.h" +# include "math.h" +# include "text.h" +# +# if DUFFLE_WINDOWS +# include "win32.h" +# endif +#endif + +CLANG_OPTIMIZE_DISABLE + +// Most of this referenced from the RAD Debugger codebase. +typedef Enum_(U4,AccessFlags) { + Bit_(AccessFlag_Read, 0), + Bit_(AccessFlag_Write, 1), + Bit_(AccessFlag_Execute, 2), + Bit_(AccessFlag_Append, 3), + Bit_(AccessFlag_ShareRead, 4), + Bit_(AccessFlag_ShareWrite, 5), + Bit_(AccessFlag_Inherited, 6), +}; + +typedef U4 FilePropertyFlags; +enum { + Bit_(FilePropertyFlag_IsFolder, 0), +}; + +typedef Struct_(FileProperties) { + U8 size; + DenseTime modified; + DenseTime created; + FilePropertyFlags flags; +}; + +typedef Struct_(File) { U8 ptr[1]; }; + +FI_ File file_zero() { File f = {0}; return f; } + +typedef Struct_(Scope_FileInfo) { File f; B4 once; }; + +FI_ B4 file_match(File a, File b) { return mem_match_struct(& a, & b); } + +os_layer void file_close(File file); +os_layer File file_open(FArena* scratch, AccessFlags flags, Str8 path); +#define file_scope(scratch, flags, path) scope_info(Scope_FileInfo, {.f = file_open(scratch, flags, path)}, file_close(info.f)) + +os_layer FileProperties properties_from_file(File file); +os_layer U8 file_read(File file, R1_U8 rng, U1* out_data); + +internal Slice_U1 +data_from_file_range(FArena* arena, File file, R1_U8 range) { + U8 pre_pos = farena_save(arena[0]); + U8 len = span_r1u8(range); + Slice_U1 result = farena_push_array(arena, U1, len); + U8 actual_read_size = file_read(file, range, result.ptr); if (actual_read_size < result.len) { + farena_rewind(arena, pre_pos + actual_read_size); result.len = actual_read_size; + } + return result; +} + +I_ Slice_U1 +data_from_file_path(FArena* arena, Str8 path, FArena* scratch) { file_scope(scratch, AccessFlag_Read | AccessFlag_ShareRead, path) { + FileProperties props = properties_from_file(info.f); + Slice_U1 data = data_from_file_range(arena, info.f, r1u8(0, props.size)); return data; +} unreachable(); } + +CLANG_OPTIMIZE_ENABLE diff --git a/code/duffle/math.h b/code/duffle/math.h new file mode 100644 index 0000000..4914623 --- /dev/null +++ b/code/duffle/math.h @@ -0,0 +1,42 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "dsl.h" +# include "analysis.h" +#endif + +#pragma region Math +#define u8_max 0xffffffffffffffffull + +#define min(A,B) (((A) < (B)) ? (A) : (B)) +#define max(A,B) (((A) > (B)) ? (A) : (B)) +#define clamp_bot(X,B) max(X, B) // Clamp "X" by "B" + +#define clamp_decrement(X) (((X) > 0) ? ((X) - 1) : 0) + +typedef Struct_(R1_U1){ U1 p0; U1 p1; }; +typedef Struct_(R1_U2){ U2 p0; U2 p1; }; +typedef Struct_(R1_U4){ U4 p0; U2 p1; }; +typedef Struct_(R1_U8){ U8 p0; U8 p1; }; + +#define r1u8(p0,p1) (R1_U8){p0,p1} + +typedef Struct_(V2_U1){ U1 x; U1 y;}; + +FI_ B8 add_of (U8 a, U8 b, U8*R_ res) { return __builtin_uaddll_overflow(a, b, res); } +FI_ B8 sub_of (U8 a, U8 b, U8*R_ res) { return __builtin_usubll_overflow(a, b, res); } +FI_ B8 mul_of (U8 a, U8 b, U8*R_ res) { return __builtin_umulll_overflow(a, b, res); } +FI_ B8 add_s_of(S8 a, S8 b, S8*R_ res) { return __builtin_saddll_overflow(a, b, res); } +FI_ B8 sub_s_of(S8 a, S8 b, S8*R_ res) { return __builtin_ssubll_overflow(a, b, res); } +FI_ B8 mul_s_of(S8 a, S8 b, S8*R_ res) { return __builtin_smulll_overflow(a, b, res); } + +FI_ U8 span_r1u8(R1_U8 r) {U8 c = ((r.p1 > r.p0) ? (r.p1 - r.p0) : 0); return c;} +#pragma endregion Math + +#pragma region Numerics + +enum { + Max_U4 = 0xffffffff +}; + +FI_ U2 Csafe_u2u4(U4 x) { assert_always(x <= Max_U4); return C_(U2, x); } +#pragma endregion Numerics diff --git a/code/duffle/memory.h b/code/duffle/memory.h index 5ddba72..8ec9196 100644 --- a/code/duffle/memory.h +++ b/code/duffle/memory.h @@ -33,6 +33,11 @@ FI_ U8 mem_copy_overlapping(U8 dest, U8 src, U8 len) { return (U8)(__builtin_m FI_ U8 mem_fill (U8 dest, U8 value, U8 len) { return (U8)(__builtin_memset ((void*)dest, (int) value, len)); } FI_ B4 mem_zero (U8 dest, U8 len) { if(dest == 0){return false;} mem_fill(dest, 0, len); return true; } +FI_ U8 mem_compare(U8 a, U8 b, U8 len) { return (U8)(__builtin_memcmp((void const*)a, (void const*)b, len)); } +FI_ B4 mem_match (U8 a, U8 b, U8 z) { return mem_compare(a, b, z) == 0; } + +#define mem_match_struct(a,b) mem_match(C_(U8,a), C_(U8,b), S_((a)[0])) + #pragma region DAG #define check_nil(nil, p) ((p) == 0 || (p) == nil) @@ -68,17 +73,16 @@ typedef Struct_(Slice) { U8 ptr; U8 len; }; // Untyped Slice FI_ Slice slice_ut_(U8 ptr, U8 len) { return (Slice){ptr, len}; } #define Slice_(type) Struct_(tmpl(Slice,type)) { type* ptr; U8 len; } -typedef Slice_(B1); #define slice_assert(s) do { assert((s).ptr != 0); assert((s).len > 0); } while(0) #define slice_end(slice) ((slice).ptr + (slice).len) #define S_slice(s) ((s).len * S_((s).ptr[0])) -#define slice_ut(ptr,len) slice_ut_(u4_(ptr), u4_(len)) -#define slice_ut_arr(a) slice_ut_(u4_(a), S_(a)) -#define slice_to_ut(s) slice_ut_(u4_((s).ptr), S_slice(s)) +#define slice_ut(ptr,len) slice_ut_(u8_(ptr), u8_(len)) +#define slice_ut_arr(a) slice_ut_(u8_(a), S_(a)) +#define slice_to_ut(s) slice_ut_(u8_((s).ptr), S_slice(s)) #define slice_iter(container, iter) (T_((container).ptr) iter = (container).ptr; iter != slice_end(container); ++ iter) -#define slice_arg_from_array(type, ...) & (tmpl(Slice,type)) { .ptr = array_decl(type,__VA_ARGS__), .len = array_len( array_decl(type,__VA_ARGS__)) } +#define slice_arg_from_array(type, ...) & (tmpl(Slice,type)) { .ptr = Array_decl(type,__VA_ARGS__), .len = Array_len( Array_decl(type,__VA_ARGS__)) } #define slice_from_array(type, array) (tmpl(Slice,type)) { .ptr = array, .len = S_(array) } FI_ void slice_zero_(Slice s) { slice_assert(s); mem_zero(s.ptr, s.len); } @@ -91,11 +95,15 @@ FI_ void slice_copy_(Slice dest, Slice src) { mem_copy(dest.ptr, src.ptr, src.len); } #define slice_copy(dest, src) do { \ - static_assert(T_same(dest, src)); \ + static_assert(T_same(dest, src), "slices are not the same type"); \ slice_copy_(slice_to_ut(dest), slice_to_ut(src)); \ } while(0) +typedef Slice_(B1); +typedef Slice_(U1); +typedef Slice_(U2); typedef Slice_(U4); +typedef Slice_(U8); #pragma endregion Slice diff --git a/code/duffle/text.h b/code/duffle/text.h index bb95c8f..1602258 100644 --- a/code/duffle/text.h +++ b/code/duffle/text.h @@ -2,13 +2,14 @@ # pragma once # include "dsl.h" # include "memory.h" +# include "encoding.h" # include "hashing.h" # include "tables.h" # include "analysis.h" #endif // NOTE(rjf): Includes reverses for uppercase and lowercase hex. -RO_ global U8 integer_symbol_reverse[128] = { +RO_ U8 integer_symbol_reverse[128] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, @@ -204,3 +205,30 @@ FI_ void str8gen_append_fmt(Str8Gen_R gen, Str8 fmt, KTL_Str8 tbl) { gen->len += result.len; } #define str8gen_append_str8_(gen, s) str8gen_append_str8(gen, str8(s)) + +// Dealing with Wides (UTF16) + +typedef U4 UTF16; +typedef Struct_(Str16) { UTF16* ptr; U8 len; }; +typedef Str16 Slice_UTF16; +#define str16(p,l) (Str16){p,l} + +internal Str16 +str16_from_8(FArena* arena, Str8 in) { + Str16 result = {0}; if (in.len) { + U8 cap = in.len * 2; + Slice_U2 str = farena_push_array(arena, U2, cap + 1); + U1* ptr = in.ptr; + U1* opl = ptr + in.len; + U8 size = 0; + UnicodeDecode consume; + for(;ptr < opl; ptr += consume.inc) + { + consume = utf8_decode(ptr, opl - ptr); + size += utf16_encode(str.ptr + size, consume.codepoint); + } + str.ptr[size] = 0; farena_rewind(arena, (cap - size) * 2); + result = str16(C_(UTF16*, str.ptr), size); + } + return result; +} diff --git a/code/duffle/win32.h b/code/duffle/win32.h index cb42b28..f3d37c2 100644 --- a/code/duffle/win32.h +++ b/code/duffle/win32.h @@ -17,17 +17,61 @@ typedef Struct_(MS_Handle){U8 id;}; #pragma endregion IO // --- WinAPI Minimal Definitions --- +typedef Struct_(MS_OVERLAPPED) { + void* Internal; + void* InternalHigh; + union { + struct { + U4 Offset; + U4 OffsetHigh; + }; + void* Pointer; + }; + + MS_Handle hEvent; +}; +typedef Struct_(MS_SECURITY_ATTRIBUTES) { + U4 nLength; + void* lpSecurityDescriptor; + B4 bInheritHandle; +}; +typedef struct MS_SYSTEMTIME { + U2 wYear; + U2 wMonth; + U2 wDayOfWeek; + U2 wDay; + U2 wHour; + U2 wMinute; + U2 wSecond; + U2 wMilliseconds; +} MS_SYSTEMTIME; +typedef struct MS_FILETIME { + U4 dwLowDateTime; + U4 dwHighDateTime; +} MS_FILETIME; +typedef struct MS_BY_HANDLE_FILE_INFORMATION { + U4 dwFileAttributes; + MS_FILETIME ftCreationTime; + MS_FILETIME ftLastAccessTime; + MS_FILETIME ftLastWriteTime; + U4 dwVolumeSerialNumber; + U4 nFileSizeHigh; + U4 nFileSizeLow; + U4 nNumberOfLinks; + U4 nFileIndexHigh; + U4 nFileIndexLow; +} MS_BY_HANDLE_FILE_INFORMATION; typedef struct MS_WNDCLASSA { - U4 style; - S8 (*lpfnWndProc)(void*, U4, U8, S8); - S4 cbClsExtra; - S4 cbWndExtra; - void* hInstance; - void* hIcon; - void* hCursor; - void* hbrBackground; - char const* lpszMenuName; - char const* lpszClassName; + U4 style; + S8 (*lpfnWndProc)(void*, U4, U8, S8); + S4 cbClsExtra; + S4 cbWndExtra; + void* hInstance; + void* hIcon; + void* hCursor; + void* hbrBackground; + char const* lpszMenuName; + char const* lpszClassName; } MS_WNDCLASSA; typedef struct MS_POINT { S4 x, y; } MS_POINT; typedef struct MS_MSG { void* hwnd; U4 message; U8 wParam; S8 lParam; U4 time; MS_POINT pt; } MS_MSG; @@ -35,43 +79,47 @@ typedef struct MS_RECT { S4 left, top, right, bottom; } MS_RECT; typedef struct MS_PAINTSTRUCT { void* hdc; S4 fErase; MS_RECT rcPaint; S4 fRestore; S4 fIncUpdate; U1 rgbReserved[32]; } MS_PAINTSTRUCT; // --- Kernel32 --- +WinAPI U4 ms_get_last_error() asm("GetLastError"); WinAPI void ms_exit_process(U4 uExitCode) asm("ExitProcess"); WinAPI MS_Handle ms_get_std_handle(U4 handle_type) asm("GetStdHandle"); WinAPI void* ms_virtual_alloc(void* lpAddress, U8 dwSize, U4 flAllocationType, U4 flProtect) asm("VirtualAlloc"); WinAPI B4 ms_read_console( - MS_Handle handle, - UTF8_R buffer, - U4 to_read, - U4_R num_read, - U8 reserved_input_control + MS_Handle handle, + UTF8_R buffer, + U4 to_read, + U4_R num_read, + U8 reserved_input_control ) asm("ReadConsoleA"); WinAPI B4 ms_write_console( - MS_Handle handle, - UTF8 const*R_ buffer, - U4 chars_to_write, - U4_V chars_written, - U8 reserved + MS_Handle handle, + UTF8 const*R_ buffer, + U4 chars_to_write, + U4_V chars_written, + U8 reserved ) asm("WriteConsoleA"); -WinAPI void* ms_create_file_a(char const* lpFileName, U4 dwDesiredAccess, U4 dwShareMode, void* lpSecurityAttributes, U4 dwCreationDisposition, U4 dwFlagsAndAttributes, void* hTemplateFile) asm("CreateFileA"); -WinAPI B4 ms_write_file(void* hFile, void const* lpBuffer, U4 nNumberOfBytesToWrite, U4* lpNumberOfBytesWritten, void* lpOverlapped) asm("WriteFile"); -WinAPI B4 ms_read_file(void* hFile, void* lpBuffer, U4 nNumberOfBytesToRead, U4* lpNumberOfBytesRead, void* lpOverlapped) asm("ReadFile"); -WinAPI B4 ms_close_handle(void* hObject) asm("CloseHandle"); +WinAPI B4 ms_get_file_information_by_handle(MS_Handle* handle, MS_BY_HANDLE_FILE_INFORMATION* file_information) asm("GetFileInformationByHandle"); +WinAPI MS_Handle* ms_create_file_a(char const* lpFileName, U4 dwDesiredAccess, U4 dwShareMode, void* lpSecurityAttributes, U4 dwCreationDisposition, U4 dwFlagsAndAttributes, void* hTemplateFile) asm("CreateFileA"); +WinAPI MS_Handle* ms_create_file_w(U2 const* lpFileName, U4 dwDesiredAccess, U4 dwShareMode, void* lpSecurityAttributes, U4 dwCreationDisposition, U4 dwFlagsAndAttributes, void* hTemplateFile) asm("CreateFileW"); +WinAPI B4 ms_write_file(void* hFile, void const* lpBuffer, U4 nNumberOfBytesToWrite, U4* lpNumberOfBytesWritten, void* lpOverlapped) asm("WriteFile"); +WinAPI B4 ms_read_file(MS_Handle* hFile, void* lpBuffer, U4 nNumberOfBytesToRead, U4* lpNumberOfBytesRead, void* lpOverlapped) asm("ReadFile"); +WinAPI B4 ms_close_handle(void* hObject) asm("CloseHandle"); +WinAPI B4 ms_filetime_to_systemtime(void const* lpFileTime, void* lpSystemTime) asm("FileTimeToSystemTime"); // --- User32 --- WinAPI U2 ms_register_class_a(MS_WNDCLASSA const* lpWndClass) asm("RegisterClassA"); WinAPI void* ms_create_window_ex_a( - U4 dwExStyle, - char const* lpClassName, - char const* lpWindowName, - U4 dwStyle, - S4 X, - S4 Y, - S4 nWidth, - S4 nHeight, - void* hWndParent, - void* hMenu, - void* hInstance, - void* lpParam + U4 dwExStyle, + char const* lpClassName, + char const* lpWindowName, + U4 dwStyle, + S4 X, + S4 Y, + S4 nWidth, + S4 nHeight, + void* hWndParent, + void* hMenu, + void* hInstance, + void* lpParam ) asm("CreateWindowExA"); WinAPI S4 ms_show_window(void* hWnd, S4 nCmdShow) asm("ShowWindow"); WinAPI S4 ms_get_message_a(MS_MSG* lpMsg, void* hWnd, U4 wMsgFilterMin, U4 wMsgFilterMax) asm("GetMessageA"); @@ -90,20 +138,20 @@ WinAPI U4 ms_set_bk_color(void* hdc, U4 color) as WinAPI S4 ms_text_out_a(void* hdc, S4 x, S4 y, char const* lpString, S4 c) asm("TextOutA"); WinAPI void* ms_get_stock_object(S4 i) asm("GetStockObject"); WinAPI void* ms_create_font_a( - S4 cHeight, - S4 cWidth, - S4 cEscapement, - S4 cOrientation, - S4 cWeight, - U4 bItalic, - U4 bUnderline, - U4 bStrikeOut, - U4 iCharSet, - U4 iOutPrecision, - U4 iClipPrecision, - U4 iQuality, - U4 iPitchAndFamily, - char const* pszFaceName + S4 cHeight, + S4 cWidth, + S4 cEscapement, + S4 cOrientation, + S4 cWeight, + U4 bItalic, + U4 bUnderline, + U4 bStrikeOut, + U4 iCharSet, + U4 iOutPrecision, + U4 iClipPrecision, + U4 iQuality, + U4 iPitchAndFamily, + char const* pszFaceName ) asm("CreateFontA"); WinAPI void* ms_create_compatible_dc(void* hdc) asm("CreateCompatibleDC"); WinAPI void* ms_create_compatible_bitmap(void* hdc, S4 cx, S4 cy) asm("CreateCompatibleBitmap"); @@ -116,12 +164,22 @@ WinAPI S4 ms_set_bk_mode(void* hdc, S4 mode) asm WinAPI void* ms_create_solid_brush(U4 color) asm("CreateSolidBrush"); WinAPI S4 ms_delete_object(void* ho) asm("DeleteObject"); +#define MS_INVALID_HANDLE_VALUE ((MS_Handle*)(U8) - 1) + enum { - MS_GENERIC_READ = 0x80000000, - MS_GENERIC_WRITE = 0x40000000, - MS_CREATE_ALWAYS = 2, - MS_OPEN_EXISTING = 3, - MS_FILE_ATTRIBUTE_NORMAL = 0x80, + MS_GENERIC_READ = 0x80000000, + MS_GENERIC_WRITE = 0x40000000, + MS_GENERIC_EXECUTE = 0x20000000L, + MS_CREATE_ALWAYS = 2, + MS_OPEN_EXISTING = 3, + MS_OPEN_ALWAYS = 4, + + MS_FILE_APPEND_DATA = 0x0004, + MS_FILE_ATTRIBUTE_NORMAL = 0x80, + MS_FILE_ATTRIBUTE_DIRECTORY = 0x00000010, + MS_FILE_SHARE_READ = 0x00000001, + MS_FILE_SHARE_WRITE = 0x00000002, + MS_FILE_SHARE_DELETE = 0x00000004, MS_MEM_COMMIT = 0x00001000, MS_MEM_RESERVE = 0x00002000, @@ -167,3 +225,92 @@ enum { #if BUILD_DEBUG FI_ void assert(U8 cond) { if(cond){return;} else{debug_trap(); ms_exit_process(1);} } #endif + +// Layer Implementation + + +#if DUFFLE_WINDOWS +I_ void +w32_date_time_from_system_time(DateTime* out, MS_SYSTEMTIME* in) { + out->year = in->wYear; + out->month = in->wMonth - 1; + out->week_day = in->wDayOfWeek; + out->day = in->wDay; + out->hour = in->wHour; + out->min = in->wMinute; + out->sec = in->wSecond; + out->msec = in->wMilliseconds; +} + +I_ void +w32_dense_time_from_file_time(DenseTime* out, MS_FILETIME* in) { + MS_SYSTEMTIME systime = {0}; ms_filetime_to_systemtime(in, &systime); DateTime date_time = {0}; + w32_date_time_from_system_time(&date_time, &systime); *out = dense_time_from_date_time(date_time); +} + +I_ FilePropertyFlags +w32_file_property_flags_from_dwFileAttributes(U4 dwFileAttributes) { + FilePropertyFlags flags = 0; if (dwFileAttributes & MS_FILE_ATTRIBUTE_DIRECTORY) { flags |= FilePropertyFlag_IsFolder; } return flags; +} + +I_ FileProperties +properties_from_file(File file) { + if (file_match(file, file_zero())) { FileProperties r = {0}; return r; } + FileProperties props = {0}; MS_Handle* handle = C_(MS_Handle*,file.ptr[0]); + MS_BY_HANDLE_FILE_INFORMATION info; S4 info_good = ms_get_file_information_by_handle(handle, &info); + if (info_good) { + U4 size_lo = info.nFileSizeLow; U4 size_hi = info.nFileSizeHigh; + props.size = C_(U8,size_lo) | (C_(U8,size_hi)<<32); + w32_dense_time_from_file_time(& props.modified, & info.ftLastWriteTime); + w32_dense_time_from_file_time(& props.created, & info.ftCreationTime); + props.flags = w32_file_property_flags_from_dwFileAttributes(info.dwFileAttributes); + } + return props; +} + +internal File +file_open(FArena* scratch, AccessFlags flags, Str8 path) { + File result = {0}; + Str16 path16 = str16_from_8(scratch, path); + U4 access_flags = 0; + U4 share_mode = 0; + U4 creation_disposition = MS_OPEN_EXISTING; + MS_SECURITY_ATTRIBUTES security_attributes = {sizeof(security_attributes), 0, 0}; + if (flags & AccessFlag_Read) { access_flags |= MS_GENERIC_READ; } + if (flags & AccessFlag_Write) { access_flags |= MS_GENERIC_WRITE; } + if (flags & AccessFlag_Execute) { access_flags |= MS_GENERIC_EXECUTE; } + if (flags & AccessFlag_ShareRead) { share_mode |= MS_FILE_SHARE_READ; } + if (flags & AccessFlag_ShareWrite) { share_mode |= MS_FILE_SHARE_WRITE | MS_FILE_SHARE_DELETE; } + if (flags & AccessFlag_Write) { creation_disposition = MS_CREATE_ALWAYS; } + if (flags & AccessFlag_Append) { creation_disposition = MS_OPEN_ALWAYS; access_flags |= MS_FILE_APPEND_DATA; } + if (flags & AccessFlag_Inherited) { security_attributes.bInheritHandle = 1; } + MS_Handle* file = ms_create_file_w(C_(U2 const*,path16.ptr), access_flags, share_mode, &security_attributes, creation_disposition, MS_FILE_ATTRIBUTE_NORMAL, 0); + if(file != MS_INVALID_HANDLE_VALUE) { result.ptr[0] = C_(U8,file); } + else { + U4 err = ms_get_last_error(); (void)err; + } + return result; +} + +internal void file_close(File file) { + if(file_match(file, file_zero())) { return; } + MS_Handle* handle = C_(MS_Handle*,file.ptr[0]); + B4 result = ms_close_handle(handle); (void)result; +} + +internal U8 file_read(File file, R1_U8 rng, U1* out_data) { + if (file_match(file, file_zero())) { return 0; } + MS_Handle* handle = C_(MS_Handle*,file.ptr[0]); + U1* ptr = out_data; + U8 off = rng.p0; while (off != rng.p1) { + U8 amt64 = rng.p1 - off; + U4 amt32 = C_(U4, min(mega(32), amt64)); + U4 read_size = 0; + MS_OVERLAPPED overlapped = { .Offset = C_(U4,off), .OffsetHigh = (U4)(off >> 32) }; + if( ! ms_read_file(handle, ptr, amt32, &read_size, &overlapped)) { break; } + ptr += read_size; + off += read_size; + } + U8 total_read_size = off - rng.p0; return total_read_size; +} +#endif diff --git a/code/part_1/sim_8086.c b/code/part_1/sim_8086.c index b33171a..c868c50 100644 --- a/code/part_1/sim_8086.c +++ b/code/part_1/sim_8086.c @@ -1,14 +1,39 @@ #include "duffle/dsl.h" #include "duffle/analysis.h" +#include "duffle/math.h" #include "duffle/memory.h" +#include "duffle/hashing.h" +#include "duffle/encoding.h" +#include "duffle/tables.h" +#include "duffle/text.h" +#include "duffle/files.h" + #include "duffle/win32.h" +enum { + Scratchpad_Len = kilo(1), + FileRam_Len = kilo(16), +}; +typedef Struct_(SMemory) { + U1 Scratchpad [Scratchpad_Len]; + U1 FileRam [FileRam_Len]; +}; +global SMemory smem; +#define path_course_content "./course_content/perfaware/" +#define path_part1 path_course_content "part1/" +CLANG_OPTIMIZE_DISABLE int main() { - + FArena scratch = farena_make(slice_ut_arr(smem.Scratchpad)); + FArena file_arena = farena_make(slice_ut_arr(smem.FileRam)); + + Str8 path_listing_0037_single_register_mov = slit8(path_part1 "listing_0037_single_register_mov"); + Str8 path_listing_0037_single_register_mov_asm = slit8(path_part1 "listing_0037_single_register_mov.asm"); + Slice_U1 data = data_from_file_path(& file_arena, path_listing_0037_single_register_mov, & scratch); ms_exit_process(0); return 0; } +CLANG_OPTIMIZE_ENABLE diff --git a/perfaware.proj b/perfaware.proj index 7f4a170..c561b6b 100644 --- a/perfaware.proj +++ b/perfaware.proj @@ -3,7 +3,7 @@ target: { executable: "build/sim_8086.exe" - working_directory: "build/" + working_directory: "" enabled: 1 label: "Sim 8086" } diff --git a/scripts/build.ps1 b/scripts/build.ps1 index e9d18eb..b66773b 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -278,6 +278,7 @@ $libraries_win32 = @( 'kernel32.lib' 'user32.lib' 'gdi32.lib' + 'vcruntime.lib' ) # --- Functions --- @@ -291,11 +292,12 @@ function compile-unit { ) $compile_args = @() $compile_args += $f_std_c11 + $compile_args += $f_all_c + $compile_args += $f_ms_ex $compile_args += $f_wall $compile_args += $f_wno_attributes $compile_args += $f_exceptions_disabled $compile_args += $f_diagnostics_absolute - $compile_args += $f_optimize_none $compile_args += $f_debug foreach ($p in $include_paths) { $compile_args += ($f_include + $p) @@ -306,7 +308,8 @@ function compile-unit { $compile_args += ($f_output + $link_module) write-host "Compiling '$unit' -> '$link_module'" -ForegroundColor DarkCyan - & $compiler $compile_args + $time_to_compile = Measure-Command { & $compiler $compile_args } + write-host "Compilation took $($time_to_compile.TotalMilliseconds)ms" if ($LASTEXITCODE -ne 0) { write-error "Compilation failed for $unit. Aborting."; exit 1 } } @@ -340,7 +343,8 @@ function link-modules { $link_args += $user_link_args write-host "Linking modules into '$module'" -ForegroundColor DarkCyan - & $linker $link_args + $time_to_link = Measure-Command { & $linker $link_args } + write-host "Linking took $($time_to_link.TotalMilliseconds)ms" if ($LASTEXITCODE -ne 0) { write-error "Linking failed. Aborting."; exit 1 } } @@ -355,6 +359,9 @@ function build-part_1 { $module_c = join-path $path_build 'sim_8086.o' $compile_args = @() + $compile_args += $f_debug + $compile_args += $f_optimize_none + # $compile_args += $f_optimize_size $compile_args += ($f_define + 'BUILD_DEBUG=1') compile-unit $source_c $module_c $includes $compile_args