diff --git a/attempt_1/main.c b/attempt_1/main.c index 59d14d6..87d6843 100644 --- a/attempt_1/main.c +++ b/attempt_1/main.c @@ -5,16 +5,86 @@ #include "duffle.amd64.win32.h" -// Define Win32 VirtualAlloc and ExitProcess signature +// --- Win32 Minimal Definitions --- +typedef void* HWND; +typedef void* HMENU; +typedef void* HINSTANCE; +typedef void* HICON; +typedef void* HCURSOR; +typedef void* HBRUSH; +typedef void* HDC; + +typedef struct { + U4 style; + S8 (*lpfnWndProc)(HWND, U4, U8, S8); + U4 cbClsExtra; + U4 cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + const char* lpszMenuName; + const char* lpszClassName; +} WNDCLASSA; + +typedef struct { + S4 x, y; +} POINT; + +typedef struct { + HWND hwnd; + U4 message; + U8 wParam; + S8 lParam; + U4 time; + POINT pt; +} MSG; + +typedef struct { + S4 left, top, right, bottom; +} RECT; + +typedef struct { + HDC hdc; + U4 fErase; + RECT rcPaint; + U4 fRestore; + U4 fIncUpdate; + U1 rgbReserved[32]; +} PAINTSTRUCT; + +// Win32 API declarations WinAPI void* ms_virtual_alloc(void* addr, U8 size, U4 allocation_type, U4 protect) asm("VirtualAlloc"); WinAPI void ms_exit_process(U4 status) asm("ExitProcess"); -// Win32 constants +WinAPI U2 ms_register_class(const WNDCLASSA* lpWndClass) asm("RegisterClassA"); +WinAPI HWND ms_create_window(U4 dwExStyle, const char* lpClassName, const char* lpWindowName, U4 dwStyle, S4 X, S4 Y, S4 nWidth, S4 nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, void* lpParam) asm("CreateWindowExA"); +WinAPI B4 ms_show_window(HWND hWnd, S4 nCmdShow) asm("ShowWindow"); +WinAPI B4 ms_get_message(MSG* lpMsg, HWND hWnd, U4 wMsgFilterMin, U4 wMsgFilterMax) asm("GetMessageA"); +WinAPI B4 ms_translate_message(const MSG* lpMsg) asm("TranslateMessage"); +WinAPI S8 ms_dispatch_message(const MSG* lpMsg) asm("DispatchMessageA"); +WinAPI S8 ms_def_window_proc(HWND hWnd, U4 Msg, U8 wParam, S8 lParam) asm("DefWindowProcA"); +WinAPI void ms_post_quit_message(S4 nExitCode) asm("PostQuitMessage"); + +WinAPI HDC ms_begin_paint(HWND hWnd, PAINTSTRUCT* lpPaint) asm("BeginPaint"); +WinAPI B4 ms_end_paint(HWND hWnd, const PAINTSTRUCT* lpPaint) asm("EndPaint"); +WinAPI U4 ms_set_text_color(HDC hdc, U4 color) asm("SetTextColor"); +WinAPI U4 ms_set_bk_color(HDC hdc, U4 color) asm("SetBkColor"); +WinAPI B4 ms_text_out(HDC hdc, S4 x, S4 y, const char* lpString, S4 c) asm("TextOutA"); +WinAPI void* ms_get_stock_object(S4 i) asm("GetStockObject"); + #define MEM_COMMIT 0x00001000 #define MEM_RESERVE 0x00002000 #define PAGE_READWRITE 0x04 -// Semantic Tags (The "Colors" of ColorForth) +#define WM_DESTROY 0x0002 +#define WM_PAINT 0x000F +#define WS_OVERLAPPEDWINDOW 0x00CF0000 +#define WS_VISIBLE 0x10000000 +#define SW_SHOW 5 +#define COLOR_WINDOW 5 + +// --- Semantic Tags (The "Colors" of ColorForth) --- #define TAG_DEFINE 0x0 // RED: New word definition #define TAG_CALL 0x1 // GREEN: Call/Compile word #define TAG_DATA 0x2 // CYAN: Variable or Literal Address @@ -34,23 +104,79 @@ internal void scatter(U4 token) { tape[tape_pos++] = token; } -// Minimal u64 to hex string helper for manual "printf" replacement -internal void print_hex(U8 val) { +// Helper to convert hex value to string without CRT +internal void u32_to_hex(U4 val, char* buf) { static const char hex_chars[] = "0123456789ABCDEF"; - UTF8 buf[19] = "0x0000000000000000"; - for(S1 i = 17; i >= 2; --i) { - buf[i] = hex_chars[val & 0xF]; + buf[0] = '0'; buf[1] = 'x'; + for(S1 i = 8; i >= 1; --i) { + buf[i+1] = hex_chars[val & 0xF]; val >>= 4; } - U4 written; - ms_write_console(ms_get_std_handle(u4_(-11)), buf, 18, &written, 0); + buf[10] = '\0'; } -internal void print_str(const char* s) { - U4 len = 0; - while(s[len]) len++; - U4 written; - ms_write_console(ms_get_std_handle(u4_(-11)), (UTF8 const*)s, len, &written, 0); +// Provide memset for the compiler's implicit struct zeroing (-nostdlib) +void* memset(void* dest, int c, U8 count) { + U1* bytes = (U1*)dest; + while (count--) { + *bytes++ = (U1)c; + } + return dest; +} + +// --- Window Procedure (Event Loop) --- +S8 win_proc(HWND hwnd, U4 msg, U8 wparam, S8 lparam) { + switch (msg) { + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc = ms_begin_paint(hwnd, &ps); + + // Dark background (0x00bbggrr) + U4 bg_color = 0x001E1E1E; + ms_set_bk_color(hdc, bg_color); + + S4 x = 20; + S4 y = 20; + S4 line_height = 20; + + for (U8 i = 0; i < tape_pos; i++) { + U4 t = tape[i]; + U4 tag = UNPACK_TAG(t); + U4 val = UNPACK_VAL(t); + + U4 color = 0x00FFFFFF; // Default White + const char* prefix = ""; + + switch (tag) { + case TAG_DEFINE: color = 0x003333FF; prefix = ": "; break; // RED + case TAG_CALL: color = 0x0033FF33; prefix = "~ "; break; // GREEN + case TAG_DATA: color = 0x00FFFF33; prefix = "$ "; break; // CYAN + case TAG_IMM: color = 0x0033FFFF; prefix = "^ "; break; // YELLOW + case TAG_COMMENT: color = 0x00AAAAAA; prefix = ". "; break; // DIM/WHITE + } + + ms_set_text_color(hdc, color); + + // Print prefix + ms_text_out(hdc, x, y, prefix, 2); + + // Print hex value + char val_str[12]; + u32_to_hex(val, val_str); + ms_text_out(hdc, x + 20, y, val_str, 10); + + y += line_height; + } + + ms_end_paint(hwnd, &ps); + return 0; + } + case WM_DESTROY: { + ms_post_quit_message(0); + return 0; + } + } + return ms_def_window_proc(hwnd, msg, wparam, lparam); } void main() { @@ -67,23 +193,32 @@ void main() { scatter(PACK_TOKEN(TAG_DATA, 5)); // 5 scatter(PACK_TOKEN(TAG_IMM, 0x51415245)); // EXECUTE SQUARE - // 3. The Visual "Interpreter" Loop - print_str("--- Sourceless Tape Drive Visualization ---\n"); - for (U8 i = 0; i < tape_pos; i++) { - U4 t = tape[i]; - U4 tag = UNPACK_TAG(t); - U4 val = UNPACK_VAL(t); + // 3. Initialize Win32 Window + WNDCLASSA wc = {0}; + wc.lpfnWndProc = win_proc; + wc.hInstance = (HINSTANCE)ms_get_stock_object(0); // dummy instance + wc.lpszClassName = "ColorForthWindow"; + // Get black brush + wc.hbrBackground = (HBRUSH)ms_get_stock_object(4); // BLACK_BRUSH - switch (tag) { - case TAG_DEFINE: print_str("[RED] Define : "); break; - case TAG_CALL: print_str("[GREEN] Call : "); break; - case TAG_DATA: print_str("[CYAN] Data : "); break; - case TAG_IMM: print_str("[YELLOW] Execute: "); break; - case TAG_COMMENT: print_str("[WHITE] Note : "); break; - default: print_str("[ERROR] Unknown: "); break; - } - print_hex(val); - print_str("\n"); + if (!ms_register_class(&wc)) ms_exit_process(1); + + HWND hwnd = ms_create_window( + 0, + wc.lpszClassName, + "Sourceless Tape Drive Editor", + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 800, 600, + NULL, NULL, wc.hInstance, NULL + ); + + if (!hwnd) ms_exit_process(1); + + // 4. Message Loop + MSG msg; + while (ms_get_message(&msg, NULL, 0, 0)) { + ms_translate_message(&msg); + ms_dispatch_message(&msg); } ms_exit_process(0); diff --git a/attempt_1/winapi.sample.c b/attempt_1/winapi.sample.c new file mode 100644 index 0000000..4555927 --- /dev/null +++ b/attempt_1/winapi.sample.c @@ -0,0 +1,98 @@ +#pragma region OS +#pragma warning(push) +#pragma warning(disable: 4820) +#pragma comment(lib, "Kernel32.lib") +#pragma comment(lib, "Advapi32.lib") +#define MS_INVALID_HANDLE_VALUE ((MS_HANDLE)(S8)-1) +#define MS_ANYSIZE_ARRAY 1 +#define MS_MEM_COMMIT 0x00001000 +#define MS_MEM_RESERVE 0x00002000 +#define MS_MEM_RELEASE 0x00008000 +#define MS_MEM_LARGE_PAGES 0x20000000 +#define MS_PAGE_READWRITE 0x04 +#define MS_TOKEN_ADJUST_PRIVILEGES (0x0020) +#define MS_SE_PRIVILEGE_ENABLED (0x00000002L) +#define MS_TOKEN_QUERY (0x0008) +#define MS__TEXT(quote) L ## quote // r_winnt +#define MS_TEXT(quote) MS__TEXT(quote) // r_winnt +#define MS_SE_LOCK_MEMORY_NAME MS_TEXT("SeLockMemoryPrivilege") +typedef int MS_BOOL; +typedef unsigned long MS_DWORD; +typedef MS_DWORD* MS_PDWORD; +typedef void* MS_HANDLE; +typedef MS_HANDLE* MS_PHANDLE; +typedef long MS_LONG; +typedef S8 MS_LONGLONG; +typedef char const* MS_LPCSTR; +typedef unsigned short* MS_LPWSTR, *MS_PWSTR; +typedef void* MS_LPVOID; +typedef MS_DWORD* MS_LPDWORD; +typedef U8 MS_ULONG_PTR, *MS_PULONG_PTR; +typedef void const* MS_LPCVOID; +typedef struct MS_SECURITY_ATTRIBUTES *MS_PSECURITY_ATTRIBUTES, *MS_LPSECURITY_ATTRIBUTES; +typedef struct MS_OVERLAPPED *MS_LPOVERLAPPED; +typedef def_union(MS_LARGE_INTEGER) { struct { MS_DWORD LowPart; MS_LONG HighPart; } _; struct { MS_DWORD LowPart; MS_LONG HighPart; } u; MS_LONGLONG QuadPart; }; +typedef def_struct(MS_FILE) { void* _Placeholder; }; +typedef def_struct(MS_SECURITY_ATTRIBUTES) { MS_DWORD nLength; A4_B1 _PAD_; MS_LPVOID lpSecurityDescriptor; MS_BOOL bInheritHandle; }; +typedef def_struct(MS_OVERLAPPED) { MS_ULONG_PTR Internal; MS_ULONG_PTR InternalHigh; union { struct { MS_DWORD Offset; MS_DWORD OffsetHigh; } _; void* Pointer; } _; MS_HANDLE hEvent; }; +typedef struct MS_LUID* MS_PLUID; +typedef struct MS_LUID_AND_ATTRIBUTES* MS_PLUID_AND_ATTRIBUTES; +typedef struct MS_TOKEN_PRIVILEGES* MS_PTOKEN_PRIVILEGES; +typedef def_struct(MS_LUID) { MS_DWORD LowPart; MS_LONG HighPart; }; +typedef def_struct(MS_LUID_AND_ATTRIBUTES) { MS_LUID Luid; MS_DWORD Attributes; }; +typedef def_struct(MS_TOKEN_PRIVILEGES) { MS_DWORD PrivilegeCount; MS_LUID_AND_ATTRIBUTES Privileges[MS_ANYSIZE_ARRAY]; }; +WinAPI MS_BOOL CloseHandle(MS_HANDLE hObject); +WinAPI MS_BOOL AdjustTokenPrivileges(MS_HANDLE TokenHandle, MS_BOOL DisableAllPrivileges, MS_PTOKEN_PRIVILEGES NewState, MS_DWORD BufferLength, MS_PTOKEN_PRIVILEGES PreviousState, MS_PDWORD ReturnLength); +WinAPI MS_HANDLE GetCurrentProcess(void); +WinAPI U8 GetLargePageMinimum(void); +WinAPI MS_BOOL LookupPrivilegeValueW(MS_LPWSTR lpSystemName, MS_LPWSTR lpName, MS_PLUID lpLuid); +WinAPI MS_BOOL OpenProcessToken(MS_HANDLE ProcessHandle, MS_DWORD DesiredAccess, MS_PHANDLE TokenHandle); +WinAPI MS_LPVOID VirtualAlloc(MS_LPVOID lpAddress, U8 dwSize, MS_DWORD flAllocationType, MS_DWORD flProtect); +WinAPI MS_BOOL VirtualFree (MS_LPVOID lpAddress, U8 dwSize, MS_DWORD dwFreeType); +#pragma warning(pop) + +typedef def_struct(OS_Windows_State) { OS_SystemInfo system_info; }; +global OS_Windows_State os__windows_info; + +IA_ OS_SystemInfo* os_system_info(void) { return & os__windows_info.system_info; } +I_ +void os__enable_large_pages(void) { + MS_HANDLE token; + if (OpenProcessToken(GetCurrentProcess(), MS_TOKEN_ADJUST_PRIVILEGES | MS_TOKEN_QUERY, &token)) + { + MS_LUID luid; + if (LookupPrivilegeValueW(0, MS_SE_LOCK_MEMORY_NAME, &luid)) + { + MS_TOKEN_PRIVILEGES priv; + priv.PrivilegeCount = 1; + priv.Privileges[0].Luid = luid; + priv.Privileges[0].Attributes = MS_SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(token, 0, & priv, size_of(priv), 0, 0); + } + CloseHandle(token); + } +} +I_ +void os_init(void) { + os__enable_large_pages(); + OS_SystemInfo*R_ info = & os__windows_info.system_info; + info->target_page_size = (U8)GetLargePageMinimum(); +} +// TODO(Ed): Large pages disabled for now... (not failing gracefully) +IA_ U8 os__vmem_reserve(U8 size, Opts_vmem*R_ opts) { + assert(opts != nullptr); + void*R_ result = VirtualAlloc(cast(void*R_, opts->base_addr), size + , MS_MEM_RESERVE + // |MS_MEM_COMMIT|(opts->no_large_pages == false ? MS_MEM_LARGE_PAGES : 0) + , MS_PAGE_READWRITE + ); + return u8_(result); +} +IA_ B4 os__vmem_commit(U8 vm, U8 size, Opts_vmem*R_ opts) { + assert(opts != nullptr); + // if (opts->no_large_pages == false ) { return 1; } + B4 result = (VirtualAlloc(cast(MS_LPVOID, vm), size, MS_MEM_COMMIT, MS_PAGE_READWRITE) != 0); + return result; +} +I_ void os_vmem_release(U8 vm, U8 size) { VirtualFree(cast(MS_LPVOID, vm), 0, MS_MEM_RELEASE); } +#pragma endregion OS diff --git a/scripts/build.attempt_1.c.ps1 b/scripts/build.attempt_1.c.ps1 index f58c28a..95101e2 100644 --- a/scripts/build.attempt_1.c.ps1 +++ b/scripts/build.attempt_1.c.ps1 @@ -76,6 +76,7 @@ $linker_args += $flag_link_win_subsystem_console $linker_args += "/nodefaultlib" $linker_args += "kernel32.lib" $linker_args += "user32.lib" +$linker_args += "gdi32.lib" $linker_args += "/entry:main" $linker_args += $object @@ -85,8 +86,7 @@ write-host "Linking took $($linking_time.TotalMilliseconds)ms" write-host if ($LASTEXITCODE -eq 0) { - write-host "Running $binary..." -ForegroundColor Green - & $binary + write-host "Build Successful! Run $binary manually to see the GUI." -ForegroundColor Green } Pop-Location