all repos — xyw @ af721d715905ebb5765014c9337f39777a94395a

A minimal virtual machine and assembler for terminals.

Removed fenster and display device, renamed console into terminal.
h3rald h3rald@h3rald.com
Thu, 29 Jan 2026 11:52:36 +0100
commit

af721d715905ebb5765014c9337f39777a94395a

parent

481fe7eafa064f39b9ea831d00de282712f3ef06

M MakefileMakefile

@@ -1,54 +1,28 @@

CC = gcc -BASE_CFLAGS = -Wall -Wextra -g +CFLAGS = -Wall -Wextra -g -# fenster.h contains function bodies unless FENSTER_HEADER is defined. -# Define it for all translation units except one, so fenster_* is defined once. -CFLAGS = $(BASE_CFLAGS) -DFENSTER_HEADER -FENSTER_IMPL_CFLAGS = $(BASE_CFLAGS) -SOURCES = xyw.c xywasm.c xywrun.c devices/console.c devices/clock.c devices/display.c -OBJS = xyw.o xywasm.o xywrun.o devices/console.o devices/clock.o devices/display.o - -# Detect platform for fenster build flags -UNAME_S := $(shell uname -s 2>/dev/null) -ifeq ($(OS),Windows_NT) - PLATFORM := windows -else ifeq ($(UNAME_S),Darwin) - PLATFORM := macos -else - PLATFORM := linux -endif - -# Platform-specific flags for fenster (window + audio) -ifeq ($(PLATFORM),windows) - FENSTER_LDFLAGS := -lgdi32 -lwinmm -else ifeq ($(PLATFORM),macos) - FENSTER_LDFLAGS := -framework Cocoa -framework AudioToolbox -else - FENSTER_LDFLAGS := -lX11 -lasound -endif +SOURCES = xyw.c xywasm.c xywrun.c devices/terminal.c devices/clock.c +OBJS = xyw.o xywasm.o xywrun.o devices/terminal.o devices/clock.o .PHONY: clean xyw: $(OBJS) - $(CC) $(CFLAGS) $(OBJS) -o xyw $(LDFLAGS) $(FENSTER_LDFLAGS) + $(CC) $(CFLAGS) $(OBJS) -o xyw $(LDFLAGS) xyw.o: xyw.c xyw.h $(CC) $(CFLAGS) -c xyw.c -o xyw.o -xywrun.o: xywrun.c xyw.h fenster.h - $(CC) $(FENSTER_IMPL_CFLAGS) -c xywrun.c -o xywrun.o +xywrun.o: xywrun.c xyw.h + $(CC) $(CFLAGS) -c xywrun.c -o xywrun.o xywasm.o: xywasm.c xyw.h $(CC) $(CFLAGS) -c xywasm.c -o xywasm.o -devices/console.o: devices/console.c xyw.h - $(CC) $(CFLAGS) -c devices/console.c -o devices/console.o +devices/terminal.o: devices/terminal.c xyw.h + $(CC) $(CFLAGS) -c devices/terminal.c -o devices/terminal.o devices/clock.o: devices/clock.c xyw.h $(CC) $(CFLAGS) -c devices/clock.c -o devices/clock.o - -devices/display.o: devices/display.c xyw.h - $(CC) $(CFLAGS) -c devices/display.c -o devices/display.o clean: rm -f xyw xyw.exe $(OBJS)
D devices/console.c

@@ -1,24 +0,0 @@

-#include <stdio.h> -#include "../xyw.h" - -/* console device */ -#define CONSOLE_INPUT 0x0 -#define CONSOLE_OUTPUT 0x1 -#define CONSOLE_ERROR 0x2 -#define CONSOLE_ON_KEYPRESS 0x3 - -void console_output(xyw_byte *data, xyw_byte addr, xyw_byte *error) -{ - (void)error; - switch (addr) - { - case CONSOLE_OUTPUT: - fputc(data[addr], stdout); - fflush(stdout); - break; - case CONSOLE_ERROR: - fputc(data[addr], stderr); - fflush(stderr); - break; - } -}
D devices/console.h

@@ -1,3 +0,0 @@

-#include "../xyw.h" - -void console_output(xyw_byte *data, xyw_byte addr, xyw_byte *error);
D devices/display.c

@@ -1,32 +0,0 @@

-#include <stdio.h> -#include "../xyw.h" - -#define COLOR 0xFFFFFF - -/* display device */ -#define DISPLAY_FILL 0x40 -#define DISPLAY_X 0x41 -#define DISPLAY_Y 0x42 -#define DISPLAY_ON_RENDER 0x43 - -void display_output(xyw_byte *data, xyw_byte addr, xyw_byte *error) -{ - (void)error; - (void)data; - (void)addr; - printf("Display output called: addr=%02X\n", addr); - switch (addr) - { - case DISPLAY_FILL: - fenster_pixel(&xyw_fenster, data[DISPLAY_X], data[DISPLAY_Y]) = data[DISPLAY_FILL]; - break; - } -} - -xyw_byte display_input(xyw_byte *data, xyw_byte addr, xyw_byte *error) -{ - (void)error; - (void)data; - (void)addr; - return 0; -}
D devices/display.h

@@ -1,4 +0,0 @@

-#include "../xyw.h" - -xyw_byte display_input(xyw_byte *data, xyw_byte addr, xyw_byte *error); -void display_output(xyw_byte *data, xyw_byte addr, xyw_byte *error);
A devices/terminal.c

@@ -0,0 +1,24 @@

+#include <stdio.h> +#include "../xyw.h" + +/* terminal device */ +#define terminal_INPUT 0x0 +#define terminal_OUTPUT 0x1 +#define terminal_ERROR 0x2 +#define terminal_ON_KEYPRESS 0x3 + +void terminal_output(xyw_byte *data, xyw_byte addr, xyw_byte *error) +{ + (void)error; + switch (addr) + { + case terminal_OUTPUT: + fputc(data[addr], stdout); + fflush(stdout); + break; + case terminal_ERROR: + fputc(data[addr], stderr); + fflush(stderr); + break; + } +}
A devices/terminal.h

@@ -0,0 +1,3 @@

+#include "../xyw.h" + +void terminal_output(xyw_byte *data, xyw_byte addr, xyw_byte *error);
M examples/d6.xywexamples/d6.xyw

@@ -4,8 +4,8 @@ ; Get random number and calculate modulo 6

clock.random LDBw $6 modulo JSRw ; Print result+1 and new line -$31 ADD console.output STBw -$0d console.output STBw +$31 ADD terminal.output STBw +$0d terminal.output STBw ; Terminate $0 system.state STBw
M examples/devices.abs.xywexamples/devices.abs.xyw

@@ -6,11 +6,13 @@ .macro system.usp $FF03

.macro system.page $FF04 .macro system.on_error $FF05 -;console -.macro console.input $FF10 -.macro console.output $FF11 -.macro console.error $FF12 -.macro console.on_keypress $FF13 +;terminal +.macro terminal.input $FF10 +.macro terminal.output $FF11 +.macro terminal.error $FF12 +.macro terminal.key $FF13 +.macro terminal.modifier $FF14 +.macro terminal.on_keypress $FF15 ;clock .macro clock.year $FF20

@@ -33,14 +35,8 @@ .macro file.read $FF35

.macro file.write $FF36 .macro file.append $FF37 -;display -.macro display.fill $FF40 -.macro display.x $FF41 -.macro display.y $FF42 -.macro display.on_render $FF43 - ;beeper -.macro beeper.state $FF50 -.macro beeper.samples $FF51 -.macro beeper.n_samples $FF53 -.macro beeper.on_stop $FF55 +.macro beeper.state $FF40 +.macro beeper.samples $FF41 +.macro beeper.n_samples $FF43 +.macro beeper.on_stop $FF45
M examples/devices.xywexamples/devices.xyw

@@ -6,11 +6,13 @@ .macro system.usp $03

.macro system.page $04 .macro system.on_error $05 -;console -.macro console.input $10 -.macro console.output $11 -.macro console.error $12 -.macro console.on_keypress $13 +;terminal +.macro terminal.input $10 +.macro terminal.output $11 +.macro terminal.error $12 +.macro terminal.key $13 +.macro terminal.modifier $14 +.macro terminal.on_keypress $15 ;clock .macro clock.year $20

@@ -33,14 +35,8 @@ .macro file.read $35

.macro file.write $36 .macro file.append $37 -;display -.macro display.fill $40 -.macro display.x $41 -.macro display.y $42 -.macro display.on_render $43 - ;beeper -.macro beeper.state $50 -.macro beeper.samples $51 -.macro beeper.n_samples $53 -.macro beeper.on_stop $55 +.macro beeper.state $40 +.macro beeper.samples $41 +.macro beeper.n_samples $43 +.macro beeper.on_stop $45
M examples/helloworld.xywexamples/helloworld.xyw

@@ -13,7 +13,7 @@ ; store top of stack to register XW

POPxw .label print.loop ; dereference address in XW and print - LDBxw console.output STB + LDBxw terminal.output STB ; increment address, dereference ; go back to loop unless zero INCxw LDBxw print.loop JCNw

@@ -21,4 +21,4 @@ RTS

; store null-terminated string .label hello -.string "Hello, World!\n"+.string "Hello, World!\n"
D examples/window.xyw

@@ -1,23 +0,0 @@

-.include "devices.xyw" -; vm will skip the first 3 bytes -; and try to process metadata wrapped by --- -init JMPw -; metadata -.string "---" ; metadata marker -.string "Test Program" ; title -.string "Just a test program" ; description -.string "H3RALD" ; author -.string "2025-12-18" ; date -.string "---" ; metadata marker - -.label init -; actual program starts here -$10 display.x STB -$10 display.y STB -$1 display.fill STB -$11 display.x STB -$10 display.y STB -$1 display.fill STB -$12 display.x STB -$10 display.y STB -$1 display.fill STB
D fenster.h

@@ -1,420 +0,0 @@

-#ifndef FENSTER_H -#define FENSTER_H - -#if defined(__APPLE__) -#include <CoreGraphics/CoreGraphics.h> -#include <objc/NSObjCRuntime.h> -#include <objc/objc-runtime.h> -#elif defined(_WIN32) -#include <windows.h> -#else -#define _DEFAULT_SOURCE 1 -#include <X11/XKBlib.h> -#include <X11/Xlib.h> -#include <X11/keysym.h> -#include <time.h> -#endif - -#include <stdint.h> -#include <stdlib.h> - -struct fenster -{ - char *title; - int width; - int height; - uint32_t *buf; - int keys[256]; /* keys are mostly ASCII, but arrows are 17..20 */ - int mod; /* mod is 4 bits mask, ctrl=1, shift=2, alt=4, meta=8 */ - int x; - int y; - int mouse; -#if defined(__APPLE__) - id wnd; -#elif defined(_WIN32) - HWND hwnd; -#else - Display *dpy; - Window w; - GC gc; - XImage *img; -#endif -}; - -#ifndef FENSTER_API -#define FENSTER_API extern -#endif -FENSTER_API int fenster_open(struct fenster *f); -FENSTER_API int fenster_loop(struct fenster *f); -FENSTER_API void fenster_close(struct fenster *f); -FENSTER_API void fenster_sleep(int64_t ms); -FENSTER_API int64_t fenster_time(void); -#define fenster_pixel(f, x, y) ((f)->buf[((y) * (f)->width) + (x)]) - -#ifndef FENSTER_HEADER -#if defined(__APPLE__) -#define msg(r, o, s) ((r (*)(id, SEL))objc_msgSend)(o, sel_getUid(s)) -#define msg1(r, o, s, A, a) \ - ((r (*)(id, SEL, A))objc_msgSend)(o, sel_getUid(s), a) -#define msg2(r, o, s, A, a, B, b) \ - ((r (*)(id, SEL, A, B))objc_msgSend)(o, sel_getUid(s), a, b) -#define msg3(r, o, s, A, a, B, b, C, c) \ - ((r (*)(id, SEL, A, B, C))objc_msgSend)(o, sel_getUid(s), a, b, c) -#define msg4(r, o, s, A, a, B, b, C, c, D, d) \ - ((r (*)(id, SEL, A, B, C, D))objc_msgSend)(o, sel_getUid(s), a, b, c, d) - -#define cls(x) ((id)objc_getClass(x)) - -extern id const NSDefaultRunLoopMode; -extern id const NSApp; - -static void fenster_draw_rect(id v, SEL s, CGRect r) -{ - (void)r, (void)s; - struct fenster *f = (struct fenster *)objc_getAssociatedObject(v, "fenster"); - CGContextRef context = - msg(CGContextRef, msg(id, cls("NSGraphicsContext"), "currentContext"), - "graphicsPort"); - CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGDataProviderRef provider = CGDataProviderCreateWithData( - NULL, f->buf, f->width * f->height * 4, NULL); - CGImageRef img = - CGImageCreate(f->width, f->height, 8, 32, f->width * 4, space, - kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, - provider, NULL, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(space); - CGDataProviderRelease(provider); - CGContextDrawImage(context, CGRectMake(0, 0, f->width, f->height), img); - CGImageRelease(img); -} - -static BOOL fenster_should_close(id v, SEL s, id w) -{ - (void)v, (void)s, (void)w; - msg1(void, NSApp, "terminate:", id, NSApp); - return YES; -} - -FENSTER_API int fenster_open(struct fenster *f) -{ - msg(id, cls("NSApplication"), "sharedApplication"); - msg1(void, NSApp, "setActivationPolicy:", NSInteger, 0); - f->wnd = msg4(id, msg(id, cls("NSWindow"), "alloc"), - "initWithContentRect:styleMask:backing:defer:", CGRect, - CGRectMake(0, 0, f->width, f->height), NSUInteger, 3, - NSUInteger, 2, BOOL, NO); - Class windelegate = - objc_allocateClassPair((Class)cls("NSObject"), "FensterDelegate", 0); - class_addMethod(windelegate, sel_getUid("windowShouldClose:"), - (IMP)fenster_should_close, "c@:@"); - objc_registerClassPair(windelegate); - msg1(void, f->wnd, "setDelegate:", id, - msg(id, msg(id, (id)windelegate, "alloc"), "init")); - Class c = objc_allocateClassPair((Class)cls("NSView"), "FensterView", 0); - class_addMethod(c, sel_getUid("drawRect:"), (IMP)fenster_draw_rect, "i@:@@"); - objc_registerClassPair(c); - - id v = msg(id, msg(id, (id)c, "alloc"), "init"); - msg1(void, f->wnd, "setContentView:", id, v); - objc_setAssociatedObject(v, "fenster", (id)f, OBJC_ASSOCIATION_ASSIGN); - - id title = msg1(id, cls("NSString"), "stringWithUTF8String:", const char *, - f->title); - msg1(void, f->wnd, "setTitle:", id, title); - msg1(void, f->wnd, "makeKeyAndOrderFront:", id, nil); - msg(void, f->wnd, "center"); - msg1(void, NSApp, "activateIgnoringOtherApps:", BOOL, YES); - return 0; -} - -FENSTER_API void fenster_close(struct fenster *f) -{ - msg(void, f->wnd, "close"); -} - -// clang-format off -static const uint8_t FENSTER_KEYCODES[128] = {65,83,68,70,72,71,90,88,67,86,0,66,81,87,69,82,89,84,49,50,51,52,54,53,61,57,55,45,56,48,93,79,85,91,73,80,10,76,74,39,75,59,92,44,47,78,77,46,9,32,96,8,0,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,2,3,127,0,5,0,4,0,20,19,18,17,0}; -// clang-format on -FENSTER_API int fenster_loop(struct fenster *f) -{ - msg1(void, msg(id, f->wnd, "contentView"), "setNeedsDisplay:", BOOL, YES); - id ev = msg4(id, NSApp, - "nextEventMatchingMask:untilDate:inMode:dequeue:", NSUInteger, - NSUIntegerMax, id, NULL, id, NSDefaultRunLoopMode, BOOL, YES); - if (!ev) - return 0; - NSUInteger evtype = msg(NSUInteger, ev, "type"); - switch (evtype) - { - case 1: /* NSEventTypeMouseDown */ - f->mouse |= 1; - break; - case 2: /* NSEventTypeMouseUp*/ - f->mouse &= ~1; - break; - case 5: - case 6: - { /* NSEventTypeMouseMoved */ - CGPoint xy = msg(CGPoint, ev, "locationInWindow"); - f->x = (int)xy.x; - f->y = (int)(f->height - xy.y); - return 0; - } - case 10: /*NSEventTypeKeyDown*/ - case 11: /*NSEventTypeKeyUp:*/ - { - NSUInteger k = msg(NSUInteger, ev, "keyCode"); - f->keys[k < 127 ? FENSTER_KEYCODES[k] : 0] = evtype == 10; - NSUInteger mod = msg(NSUInteger, ev, "modifierFlags") >> 17; - f->mod = (mod & 0xc) | ((mod & 1) << 1) | ((mod >> 1) & 1); - return 0; - } - } - msg1(void, NSApp, "sendEvent:", id, ev); - return 0; -} -#elif defined(_WIN32) -// clang-format off -static const uint8_t FENSTER_KEYCODES[] = {0,27,49,50,51,52,53,54,55,56,57,48,45,61,8,9,81,87,69,82,84,89,85,73,79,80,91,93,10,0,65,83,68,70,71,72,74,75,76,59,39,96,0,92,90,88,67,86,66,78,77,44,46,47,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,17,3,0,20,0,19,0,5,18,4,26,127}; -// clang-format on -typedef struct BINFO -{ - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[3]; -} BINFO; -static LRESULT CALLBACK fenster_wndproc(HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam) -{ - struct fenster *f = (struct fenster *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - switch (msg) - { - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - HDC memdc = CreateCompatibleDC(hdc); - HBITMAP hbmp = CreateCompatibleBitmap(hdc, f->width, f->height); - HBITMAP oldbmp = SelectObject(memdc, hbmp); - BINFO bi = { - .bmiHeader = { - .biSize = sizeof(BITMAPINFOHEADER), - .biWidth = f->width, - .biHeight = -f->height, - .biPlanes = 1, - .biBitCount = 32, - .biCompression = BI_BITFIELDS, - .biSizeImage = (DWORD)(f->width * f->height * 4), - .biXPelsPerMeter = 0, - .biYPelsPerMeter = 0, - .biClrUsed = 0, - .biClrImportant = 0}, - .bmiColors = {{0}}}; - bi.bmiColors[0].rgbRed = 0xff; - bi.bmiColors[1].rgbGreen = 0xff; - bi.bmiColors[2].rgbBlue = 0xff; - SetDIBitsToDevice(memdc, 0, 0, f->width, f->height, 0, 0, 0, f->height, - f->buf, (BITMAPINFO *)&bi, DIB_RGB_COLORS); - BitBlt(hdc, 0, 0, f->width, f->height, memdc, 0, 0, SRCCOPY); - SelectObject(memdc, oldbmp); - DeleteObject(hbmp); - DeleteDC(memdc); - EndPaint(hwnd, &ps); - } - break; - case WM_CLOSE: - DestroyWindow(hwnd); - break; - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - f->mouse = (msg == WM_LBUTTONDOWN); - break; - case WM_MOUSEMOVE: - f->y = HIWORD(lParam), f->x = LOWORD(lParam); - break; - case WM_KEYDOWN: - case WM_KEYUP: - { - f->mod = ((GetKeyState(VK_CONTROL) & 0x8000) >> 15) | - ((GetKeyState(VK_SHIFT) & 0x8000) >> 14) | - ((GetKeyState(VK_MENU) & 0x8000) >> 13) | - (((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) >> 12); - f->keys[FENSTER_KEYCODES[HIWORD(lParam) & 0x1ff]] = !((lParam >> 31) & 1); - } - break; - case WM_DESTROY: - PostQuitMessage(0); - break; - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - } - return 0; -} - -FENSTER_API int fenster_open(struct fenster *f) -{ - HINSTANCE hInstance = GetModuleHandle(NULL); - WNDCLASSEX wc = {0}; - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = CS_VREDRAW | CS_HREDRAW; - wc.lpfnWndProc = fenster_wndproc; - wc.hInstance = hInstance; - wc.lpszClassName = f->title; - RegisterClassEx(&wc); - f->hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, f->title, f->title, - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - f->width, f->height, NULL, NULL, hInstance, NULL); - - if (f->hwnd == NULL) - return -1; - SetWindowLongPtr(f->hwnd, GWLP_USERDATA, (LONG_PTR)f); - ShowWindow(f->hwnd, SW_NORMAL); - UpdateWindow(f->hwnd); - return 0; -} - -FENSTER_API void fenster_close(struct fenster *f) { (void)f; } - -FENSTER_API int fenster_loop(struct fenster *f) -{ - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - return -1; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - InvalidateRect(f->hwnd, NULL, TRUE); - return 0; -} -#else -// clang-format off -static int FENSTER_KEYCODES[124] = {XK_BackSpace,8,XK_Delete,127,XK_Down,18,XK_End,5,XK_Escape,27,XK_Home,2,XK_Insert,26,XK_Left,20,XK_Page_Down,4,XK_Page_Up,3,XK_Return,10,XK_Right,19,XK_Tab,9,XK_Up,17,XK_apostrophe,39,XK_backslash,92,XK_bracketleft,91,XK_bracketright,93,XK_comma,44,XK_equal,61,XK_grave,96,XK_minus,45,XK_period,46,XK_semicolon,59,XK_slash,47,XK_space,32,XK_a,65,XK_b,66,XK_c,67,XK_d,68,XK_e,69,XK_f,70,XK_g,71,XK_h,72,XK_i,73,XK_j,74,XK_k,75,XK_l,76,XK_m,77,XK_n,78,XK_o,79,XK_p,80,XK_q,81,XK_r,82,XK_s,83,XK_t,84,XK_u,85,XK_v,86,XK_w,87,XK_x,88,XK_y,89,XK_z,90,XK_0,48,XK_1,49,XK_2,50,XK_3,51,XK_4,52,XK_5,53,XK_6,54,XK_7,55,XK_8,56,XK_9,57}; -// clang-format on -FENSTER_API int fenster_open(struct fenster *f) -{ - f->dpy = XOpenDisplay(NULL); - int screen = DefaultScreen(f->dpy); - f->w = XCreateSimpleWindow(f->dpy, RootWindow(f->dpy, screen), 0, 0, f->width, - f->height, 0, BlackPixel(f->dpy, screen), - WhitePixel(f->dpy, screen)); - f->gc = XCreateGC(f->dpy, f->w, 0, 0); - XSelectInput(f->dpy, f->w, - ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | - ButtonReleaseMask | PointerMotionMask); - XStoreName(f->dpy, f->w, f->title); - XMapWindow(f->dpy, f->w); - XSync(f->dpy, f->w); - f->img = XCreateImage(f->dpy, DefaultVisual(f->dpy, 0), 24, ZPixmap, 0, - (char *)f->buf, f->width, f->height, 32, 0); - return 0; -} -FENSTER_API void fenster_close(struct fenster *f) { XCloseDisplay(f->dpy); } -FENSTER_API int fenster_loop(struct fenster *f) -{ - XEvent ev; - XPutImage(f->dpy, f->w, f->gc, f->img, 0, 0, 0, 0, f->width, f->height); - XFlush(f->dpy); - while (XPending(f->dpy)) - { - XNextEvent(f->dpy, &ev); - switch (ev.type) - { - case ButtonPress: - case ButtonRelease: - f->mouse = (ev.type == ButtonPress); - break; - case MotionNotify: - f->x = ev.xmotion.x, f->y = ev.xmotion.y; - break; - case KeyPress: - case KeyRelease: - { - int m = ev.xkey.state; - int k = XkbKeycodeToKeysym(f->dpy, ev.xkey.keycode, 0, 0); - for (unsigned int i = 0; i < 124; i += 2) - { - if (FENSTER_KEYCODES[i] == k) - { - f->keys[FENSTER_KEYCODES[i + 1]] = (ev.type == KeyPress); - break; - } - } - f->mod = (!!(m & ControlMask)) | (!!(m & ShiftMask) << 1) | - (!!(m & Mod1Mask) << 2) | (!!(m & Mod4Mask) << 3); - } - break; - } - } - return 0; -} -#endif - -#ifdef _WIN32 -FENSTER_API void fenster_sleep(int64_t ms) { Sleep(ms); } -FENSTER_API int64_t fenster_time() -{ - LARGE_INTEGER freq, count; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&count); - return (int64_t)(count.QuadPart * 1000.0 / freq.QuadPart); -} -#else -FENSTER_API void fenster_sleep(int64_t ms) -{ - struct timespec ts; - ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000000; - nanosleep(&ts, NULL); -} -FENSTER_API int64_t fenster_time(void) -{ - struct timespec time; - clock_gettime(CLOCK_REALTIME, &time); - return time.tv_sec * 1000 + (time.tv_nsec / 1000000); -} -#endif - -#ifdef __cplusplus -class Fenster -{ - struct fenster f; - int64_t now; - -public: - Fenster(const int w, const int h, const char *title) - : f{.title = title, .width = w, .height = h} - { - this->f.buf = new uint32_t[w * h]; - this->now = fenster_time(); - fenster_open(&this->f); - } - ~Fenster() - { - fenster_close(&this->f); - delete[] this->f.buf; - } - bool loop(const int fps) - { - int64_t t = fenster_time(); - if (t - this->now < 1000 / fps) - { - fenster_sleep(t - now); - } - this->now = t; - return fenster_loop(&this->f) == 0; - } - inline uint32_t &px(const int x, const int y) - { - return fenster_pixel(&this->f, x, y); - } - bool key(int c) { return c >= 0 && c < 128 ? this->f.keys[c] : false; } - int x() { return this->f.x; } - int y() { return this->f.y; } - int mouse() { return this->f.mouse; } - int mod() { return this->f.mod; } -}; -#endif /* __cplusplus */ - -#endif /* !FENSTER_HEADER */ -#endif /* FENSTER_H */
D fenster_audio.h

@@ -1,160 +0,0 @@

-#ifndef FENSTER_AUDIO_H -#define FENSTER_AUDIO_H - -#ifndef FENSTER_SAMPLE_RATE -#define FENSTER_SAMPLE_RATE 44100 -#endif - -#ifndef FENSTER_AUDIO_BUFSZ -#define FENSTER_AUDIO_BUFSZ 8192 -#endif - -#if defined(__APPLE__) -#include <AudioToolbox/AudioQueue.h> -struct fenster_audio { - AudioQueueRef queue; - size_t pos; - float buf[FENSTER_AUDIO_BUFSZ]; - dispatch_semaphore_t drained; - dispatch_semaphore_t full; -}; -#elif defined(_WIN32) -#include <mmsystem.h> -#include <windows.h> -struct fenster_audio { - WAVEHDR header; - HWAVEOUT wo; - WAVEHDR hdr[2]; - int16_t buf[2][FENSTER_AUDIO_BUFSZ]; -}; -#elif defined(__linux__) -struct fenster_audio { - void *pcm; - float buf[FENSTER_AUDIO_BUFSZ]; - size_t pos; -}; -#endif - -#ifndef FENSTER_API -#define FENSTER_API extern -#endif -FENSTER_API int fenster_audio_open(struct fenster_audio *f); -FENSTER_API int fenster_audio_available(struct fenster_audio *f); -FENSTER_API void fenster_audio_write(struct fenster_audio *f, float *buf, - size_t n); -FENSTER_API void fenster_audio_close(struct fenster_audio *f); - -#ifndef FENSTER_HEADER -#if defined(__APPLE__) -static void fenster_audio_cb(void *p, AudioQueueRef q, AudioQueueBufferRef b) { - struct fenster_audio *fa = (struct fenster_audio *)p; - dispatch_semaphore_wait(fa->full, DISPATCH_TIME_FOREVER); - memmove(b->mAudioData, fa->buf, sizeof(fa->buf)); - dispatch_semaphore_signal(fa->drained); - AudioQueueEnqueueBuffer(q, b, 0, NULL); -} -FENSTER_API int fenster_audio_open(struct fenster_audio *fa) { - AudioStreamBasicDescription format = {0}; - format.mSampleRate = FENSTER_SAMPLE_RATE; - format.mFormatID = kAudioFormatLinearPCM; - format.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsPacked; - format.mBitsPerChannel = 32; - format.mFramesPerPacket = format.mChannelsPerFrame = 1; - format.mBytesPerPacket = format.mBytesPerFrame = 4; - fa->drained = dispatch_semaphore_create(1); - fa->full = dispatch_semaphore_create(0); - AudioQueueNewOutput(&format, fenster_audio_cb, fa, NULL, NULL, 0, &fa->queue); - for (int i = 0; i < 2; i++) { - AudioQueueBufferRef buffer = NULL; - AudioQueueAllocateBuffer(fa->queue, FENSTER_AUDIO_BUFSZ * 4, &buffer); - buffer->mAudioDataByteSize = FENSTER_AUDIO_BUFSZ * 4; - memset(buffer->mAudioData, 0, buffer->mAudioDataByteSize); - AudioQueueEnqueueBuffer(fa->queue, buffer, 0, NULL); - } - AudioQueueStart(fa->queue, NULL); - return 0; -} -FENSTER_API void fenster_audio_close(struct fenster_audio *fa) { - AudioQueueStop(fa->queue, false); - AudioQueueDispose(fa->queue, false); -} -FENSTER_API int fenster_audio_available(struct fenster_audio *fa) { - if (dispatch_semaphore_wait(fa->drained, DISPATCH_TIME_NOW)) - return 0; - return FENSTER_AUDIO_BUFSZ - fa->pos; -} -FENSTER_API void fenster_audio_write(struct fenster_audio *fa, float *buf, - size_t n) { - while (fa->pos < FENSTER_AUDIO_BUFSZ && n > 0) { - fa->buf[fa->pos++] = *buf++, n--; - } - if (fa->pos >= FENSTER_AUDIO_BUFSZ) { - fa->pos = 0; - dispatch_semaphore_signal(fa->full); - } -} -#elif defined(_WIN32) -FENSTER_API int fenster_audio_open(struct fenster_audio *fa) { - WAVEFORMATEX wfx = {WAVE_FORMAT_PCM, 1, FENSTER_SAMPLE_RATE, FENSTER_SAMPLE_RATE * 2, 1, 16, 0}; - waveOutOpen(&fa->wo, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL); - for (int i = 0; i < 2; i++) { - fa->hdr[i].lpData = fa->buf[i]; - fa->hdr[i].dwBufferLength = FENSTER_AUDIO_BUFSZ * 2; - waveOutPrepareHeader(fa->wo, &fa->hdr[i], sizeof(WAVEHDR)); - waveOutWrite(fa->wo, &fa->hdr[i], sizeof(WAVEHDR)); - } - return 0; -} -FENSTER_API int fenster_audio_available(struct fenster_audio *fa) { - for (int i = 0; i < 2; i++) - if (fa->hdr[i].dwFlags & WHDR_DONE) - return FENSTER_AUDIO_BUFSZ; - return 0; -} -FENSTER_API void fenster_audio_write(struct fenster_audio *fa, float *buf, - size_t n) { - for (int i = 0; i < 2; i++) { - if (fa->hdr[i].dwFlags & WHDR_DONE) { - for (unsigned j = 0; j < n; j++) { - fa->buf[i][j] = (int16_t)(buf[j] * 32767); - } - waveOutWrite(fa->wo, &fa->hdr[i], sizeof(WAVEHDR)); - return; - } - } -} -FENSTER_API void fenster_audio_close(struct fenster_audio *fa) { - waveOutClose(fa->wo); -} -#elif defined(__linux__) -int snd_pcm_open(void **, const char *, int, int); -int snd_pcm_set_params(void *, int, int, int, int, int, int); -int snd_pcm_avail(void *); -int snd_pcm_writei(void *, const void *, unsigned long); -int snd_pcm_recover(void *, int, int); -int snd_pcm_close(void *); -FENSTER_API int fenster_audio_open(struct fenster_audio *fa) { - if (snd_pcm_open(&fa->pcm, "default", 0, 0)) - return -1; - int fmt = (*(unsigned char *)(&(uint16_t){1})) ? 14 : 15; - return snd_pcm_set_params(fa->pcm, fmt, 3, 1, FENSTER_SAMPLE_RATE, 1, 100000); -} -FENSTER_API int fenster_audio_available(struct fenster_audio *fa) { - int n = snd_pcm_avail(fa->pcm); - if (n < 0) - snd_pcm_recover(fa->pcm, n, 0); - return n; -} -FENSTER_API void fenster_audio_write(struct fenster_audio *fa, float *buf, - size_t n) { - int r = snd_pcm_writei(fa->pcm, buf, n); - if (r < 0) - snd_pcm_recover(fa->pcm, r, 0); -} -FENSTER_API void fenster_audio_close(struct fenster_audio *fa) { - snd_pcm_close(fa->pcm); -} -#endif - -#endif /* FENSTER_HEADER */ -#endif /* FENSTER_AUDIO_H */
M xyw.cxyw.c

@@ -3,7 +3,6 @@ #include <string.h>

#include "xyw.h" int xyw_debug = 0; -int xyw_zoom = 1; // Instruction mnemonics definition const char xyw_instructions[][4] = {

@@ -37,15 +36,11 @@ if (flag(argv[i], "debug"))

{ xyw_debug = 1; } - if (flag(argv[i], "zoom")) - { - xyw_zoom = 2; - } } for (int i = 1; i < argc; i++) { - if (flag(argv[i], "debug") || flag(argv[i], "zoom")) + if (flag(argv[i], "debug")) { continue; // already handled }
M xyw.hxyw.h

@@ -1,16 +1,11 @@

#ifndef XYW_H #define XYW_H -#include "fenster.h" - #define XYW_MODE_X 0x20 #define XYW_MODE_Y 0x40 #define XYW_MODE_W 0x80 #define XYW_TOTAL_INSTRUCTIONS 0x20 #define XYW_TOTAL_DEVICES 0x10 - -#define XYW_WIDTH 256 -#define XYW_HEIGHT 256 // clang-format off #define XYW_PEEKW(d) (*(d) << 8 | (d)[1])

@@ -38,8 +33,6 @@ // clang-format on

extern const char xyw_instructions[][4]; extern int xyw_debug; -extern int xyw_zoom; -extern struct fenster xyw_fenster; extern xyw_device xyw_devices[XYW_TOTAL_DEVICES]; int xyw_assemble(const char *input, const char *output);
M xywrun.cxywrun.c

@@ -2,9 +2,8 @@ #include <stdio.h>

#include <stdlib.h> #include "xyw.h" -#include "devices/console.h" +#include "devices/terminal.h" #include "devices/clock.h" -#include "devices/display.h" #define MEMORY_SIZE 0xffff #define STACK_SIZE 0xff

@@ -56,9 +55,6 @@ static xyw_word yw_storage = 0; // 16-bit Y register storage

xyw_word *pc = &pc_storage; xyw_word *xw = &xw_storage; xyw_word *yw = &yw_storage; - -// Global window instance (declared in xyw.h) -struct fenster xyw_fenster; //// Helpers to retrieve device number and address within the device static inline int get_device(xyw_word addr)

@@ -255,14 +251,12 @@

xyw_device xyw_devices[XYW_TOTAL_DEVICES] = { // System device (not implemented yet) {&xyw_memory[0xff00], 0, 0, 0}, - // Console device - {&xyw_memory[0xff10], 0, 0, console_output}, + // terminal device + {&xyw_memory[0xff10], 0, 0, terminal_output}, // Clock device {&xyw_memory[0xff20], clock_init, clock_input, 0}, // File device {&xyw_memory[0xff30], 0, 0, 0}, - // Display device - {&xyw_memory[0xff40], 0, display_input, display_output}, // ... }; // clang-format on

@@ -358,15 +352,8 @@ // Process metadata

process_metadata(); // Set direct page to device page by default xyw_memory[SYSTEM_PAGE] = 0xff; - // Initialize fenster - uint32_t buf[XYW_WIDTH * XYW_HEIGHT * xyw_zoom * xyw_zoom]; - xyw_fenster.title = title; - xyw_fenster.width = XYW_WIDTH * xyw_zoom; - xyw_fenster.height = XYW_HEIGHT * xyw_zoom; - xyw_fenster.buf = buf; - fenster_open(&xyw_fenster); xyw_byte paused = 0; - while (fenster_loop(&xyw_fenster) == 0 && xyw_memory[SYSTEM_STATE] && *pc < SYSTEM_MEMORY_START) + while (xyw_memory[SYSTEM_STATE] && *pc < SYSTEM_MEMORY_START) { if (!paused) {

@@ -414,6 +401,5 @@ // At present, JCN, JMP, JSR and RTS set the pc to 1 value less than the actual address

// because we are relying on the fact that pc will be incremented at the end of the loop (*pc)++; } - fenster_close(&xyw_fenster); return 0; }