all repos — xyw @ 79672637f5164782bdacb12a66370fe1a211ff58

A minimal virtual machine and assembler for terminals.

Minor naming refactoring.
h3rald h3rald@h3rald.com
Wed, 11 Feb 2026 17:01:53 +0100
commit

79672637f5164782bdacb12a66370fe1a211ff58

parent

6d6b6dac8364639423a553c8d541222f30e7aba1

6 files changed, 55 insertions(+), 55 deletions(-)

jump to
M devices/file.cdevices/file.c

@@ -133,14 +133,14 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);

if (path_addr == 0 || buffer_addr == 0 || length == 0) { - xyw_dbg(" Invalid parameters for file_read\n"); + XYW_DBG(" Invalid parameters for file_read\n"); *error = FILE_ERROR_INVALID_OP; return; } get_path_string(path_addr, path, FILE_MAX_PATH); - xyw_dbg(" Reading file: %s, length=%u, cursor=%ld\n", path, length, file_cursor); + XYW_DBG(" Reading file: %s, length=%u, cursor=%ld\n", path, length, file_cursor); /* Check if it's a directory - list contents (no cursor support for dirs) */ if (data[FILE_TYPE] == FILE_TYPE_DIRECTORY)

@@ -157,7 +157,7 @@ hFind = FindFirstFileA(searchPath, &findData);

if (hFind == INVALID_HANDLE_VALUE) { - xyw_dbg(" Failed to open directory: %s\n", path); + XYW_DBG(" Failed to open directory: %s\n", path); *error = FILE_ERROR_ACCESS_DENIED; return; }

@@ -212,7 +212,7 @@ char full_path[FILE_MAX_PATH * 2];

if (!dir) { - xyw_dbg(" Failed to open directory: %s\n", path); + XYW_DBG(" Failed to open directory: %s\n", path); *error = FILE_ERROR_ACCESS_DENIED; return; }

@@ -289,7 +289,7 @@ file_close();

file_handle = fopen(path, "rb"); if (!file_handle) { - xyw_dbg(" Failed to open file: %s\n", path); + XYW_DBG(" Failed to open file: %s\n", path); *error = FILE_ERROR_NOT_FOUND; return; }

@@ -302,7 +302,7 @@

/* Seek to cursor position */ if (fseek(file_handle, file_cursor, SEEK_SET) != 0) { - xyw_dbg(" Failed to seek in file: %s\n", path); + XYW_DBG(" Failed to seek in file: %s\n", path); *error = FILE_ERROR_IO_ERROR; return; }

@@ -319,7 +319,7 @@ {

xyw_memory[buffer_addr + bytes_read] = 0; } - xyw_dbg(" Read %zu bytes, cursor now at %ld\n", bytes_read, file_cursor); + XYW_DBG(" Read %zu bytes, cursor now at %ld\n", bytes_read, file_cursor); XYW_POKEW(&data[FILE_SUCCESS], (xyw_word)bytes_read); }

@@ -336,14 +336,14 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);

if (path_addr == 0 || buffer_addr == 0 || length == 0) { - xyw_dbg(" Invalid parameters for file_write\n"); + XYW_DBG(" Invalid parameters for file_write\n"); *error = FILE_ERROR_INVALID_OP; return; } get_path_string(path_addr, path, FILE_MAX_PATH); - xyw_dbg(" Writing to file: %s (append=%d), length=%u, cursor=%ld\n", path, append, length, file_cursor); + XYW_DBG(" Writing to file: %s (append=%d), length=%u, cursor=%ld\n", path, append, length, file_cursor); /* Open file if not already open, path changed, or mode changed */ int need_reopen = !file_handle ||

@@ -371,7 +371,7 @@ }

if (!file_handle) { - xyw_dbg(" Failed to open file for writing: %s (errno=%d: %s)\n", path, errno, strerror(errno)); + XYW_DBG(" Failed to open file for writing: %s (errno=%d: %s)\n", path, errno, strerror(errno)); *error = FILE_ERROR_ACCESS_DENIED; return; }

@@ -395,7 +395,7 @@

/* Seek to cursor position (for non-append continuing writes) */ if (!append && fseek(file_handle, file_cursor, SEEK_SET) != 0) { - xyw_dbg(" Failed to seek in file: %s\n", path); + XYW_DBG(" Failed to seek in file: %s\n", path); *error = FILE_ERROR_IO_ERROR; return; }

@@ -409,7 +409,7 @@ }

if (actual_length == 0) { - xyw_dbg(" Empty content for file_write\n"); + XYW_DBG(" Empty content for file_write\n"); return; }

@@ -420,7 +420,7 @@

/* Advance cursor */ file_cursor += written; - xyw_dbg(" Wrote %zu bytes (of %u max), cursor now at %ld\n", written, length, file_cursor); + XYW_DBG(" Wrote %zu bytes (of %u max), cursor now at %ld\n", written, length, file_cursor); XYW_POKEW(&data[FILE_SUCCESS], (xyw_word)written); /* Update stats after write */

@@ -438,7 +438,7 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);

if (path_addr == 0) { - xyw_dbg(" Invalid path address for file_delete\n"); + XYW_DBG(" Invalid path address for file_delete\n"); *error = FILE_ERROR_INVALID_OP; return; }

@@ -451,11 +451,11 @@ {

file_close(); } - xyw_dbg(" Deleting file: %s\n", path); + XYW_DBG(" Deleting file: %s\n", path); if (remove(path) != 0) { - xyw_dbg(" Failed to delete file: %s\n", path); + XYW_DBG(" Failed to delete file: %s\n", path); *error = FILE_ERROR_ACCESS_DENIED; return; }
M devices/terminal.cdevices/terminal.c

@@ -15,7 +15,7 @@ {

case TERMINAL_INPUT: { xyw_word handler; - if (!xyw_arguments_processed && XYW_PEEKW(&data[TERMINAL_ON_ARGUMENT])) + if (!xyw_argv_processed && XYW_PEEKW(&data[TERMINAL_ON_ARGUMENT])) { // Process input as arguments (separated by XYW_ARGUMENT_SEPARATOR) until XYW_END_OF_ARGUMENTS handler = XYW_PEEKW(&data[TERMINAL_ON_ARGUMENT]);
M xyw.cxyw.c

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

#include "xyw.h" int xyw_debug = 0; -int xyw_arguments_processed = 0; +int xyw_argv_processed = 0; char *xyw_argv[32]; int xyw_argc = 0;
M xyw.hxyw.h

@@ -9,14 +9,16 @@ #define XYW_TOTAL_DEVICES 0x10

#define XYW_ARGUMENT_SEPARATOR 0x1E #define XYW_END_OF_ARGUMENTS 0x1D +typedef unsigned char xyw_byte; +typedef unsigned short xyw_word; + // clang-format off #define XYW_PEEKW(d) (*(d) << 8 | (d)[1]) #define XYW_POKEW(d, v) { *(d) = (v) >> 8; (d)[1] = (v); } +#define XYW_DBG(...) do { if (xyw_debug) fprintf(stdout, __VA_ARGS__); } while(0) // clang-format on -typedef unsigned char xyw_byte; -typedef unsigned short xyw_word; - +// Devices API typedef xyw_byte (*xyw_input)(xyw_byte *data, xyw_byte addr, xyw_byte *error); typedef void (*xyw_output)(xyw_byte *data, xyw_byte addr, xyw_byte *error); typedef void (*xyw_init)(xyw_byte *data);

@@ -29,17 +31,15 @@ xyw_input input;

xyw_output output; } xyw_device; -// clang-format off -#define xyw_dbg(...) do { if (xyw_debug) fprintf(stdout, __VA_ARGS__); } while(0) -// clang-format on - +// Main Globals +extern xyw_device xyw_devices[XYW_TOTAL_DEVICES]; extern const char xyw_instructions[][4]; extern int xyw_debug; extern int xyw_argc; extern char *xyw_argv[]; -extern xyw_device xyw_devices[XYW_TOTAL_DEVICES]; -extern int xyw_arguments_processed; +extern int xyw_argv_processed; +// Main public API int xyw_assemble(const char *input, const char *output); int xyw_run(const char *input); int xyw_eval(xyw_word pc);
M xywasm.cxywasm.c

@@ -315,7 +315,7 @@ static int process_comment(xyw_context *ctx)

{ (void)ctx; token_type = TOKEN_TYPE_COMMENT; - xyw_dbg("Comment:\t%s\n", token); + XYW_DBG("Comment:\t%s\n", token); return 0; }

@@ -355,7 +355,7 @@ token_error("Invalid hex digit");

return -1; } } - xyw_dbg("Hex number:\t%s\t(%04X) [%s]\n", token, value, token_is_word ? "word" : "byte"); + XYW_DBG("Hex number:\t%s\t(%04X) [%s]\n", token, value, token_is_word ? "word" : "byte"); } else if (token[0] == '%') {

@@ -380,7 +380,7 @@ token_error("Invalid binary digit");

return -1; } } - xyw_dbg("Binary number:\t%s\t(%04X) [byte]\n", token, value); + XYW_DBG("Binary number:\t%s\t(%04X) [byte]\n", token, value); } else {

@@ -447,7 +447,7 @@ }

} char bits[9]; byte_to_binary(opcode, bits); - xyw_dbg("Instruction:\t%s\t(%02X - %s)\n", token, opcode, bits); + XYW_DBG("Instruction:\t%s\t(%02X - %s)\n", token, opcode, bits); token_type = TOKEN_TYPE_INSTRUCTION; token_value = opcode; append(opcode);

@@ -479,7 +479,7 @@ {

xyw_symbol *sym = &symbols[i]; if (sym->type == SYMBOL_TYPE_MACRO) { - xyw_dbg("Macro:\t\t%s -> %s\n", token, sym->contents); + XYW_DBG("Macro:\t\t%s -> %s\n", token, sym->contents); // Save context position before macro expansion int saved_line = ctx->line; int saved_column = ctx->column;

@@ -495,7 +495,7 @@ ctx->column = saved_column;

} else if (sym->type == SYMBOL_TYPE_LABEL) { - xyw_dbg("Label Ref:\t%s -> %04X\n", token, sym->address); + XYW_DBG("Label Ref:\t%s -> %04X\n", token, sym->address); // Push label address append(PSH | XYW_MODE_W); XYW_POKEW(&data[ptr], sym->address);

@@ -511,7 +511,7 @@ }

else { // Store reference to be resolved later - xyw_dbg("Reference:\t%s\n", token); + XYW_DBG("Reference:\t%s\n", token); // Push placeholder value $0000 for now append(PSH | XYW_MODE_W); if (ref(ctx, token) != 0)

@@ -538,7 +538,7 @@ if (process_symbol(ctx) != 0)

{ return -1; } - xyw_dbg("Directive:\t.label %s [$%04X]\n", token, ptr); + XYW_DBG("Directive:\t.label %s [$%04X]\n", token, ptr); label(ctx, token); return validate_single_directive_argument(ctx, r); }

@@ -551,7 +551,7 @@ {

return -1; } process_string(ctx); - xyw_dbg("Directive:\t.include %s\n", token); + XYW_DBG("Directive:\t.include %s\n", token); xyw_context include_ctx; include_ctx.src = SRC_FILE; // Ignore token quotes for file name

@@ -563,9 +563,9 @@ if (validate_single_directive_argument(ctx, r) != 0)

{ return -1; } - xyw_dbg("-> Accessing:\t%s\n", include_ctx.file); + XYW_DBG("-> Accessing:\t%s\n", include_ctx.file); int result = assemble_file(&include_ctx); - xyw_dbg("<- Continuing:\t%s\n", ctx->file); + XYW_DBG("<- Continuing:\t%s\n", ctx->file); return result; }

@@ -577,7 +577,7 @@ {

return -1; } process_string(ctx); - xyw_dbg("Directive:\t.string %s\n", token); + XYW_DBG("Directive:\t.string %s\n", token); // Store string in memory (without quotes) for (unsigned int i = 1; i < token_length - 1; i++) {

@@ -590,7 +590,7 @@

static int process_directive_byte(xyw_context *ctx) { xyw_token_terminator r; - xyw_dbg("Directive:\t.byte\n"); + XYW_DBG("Directive:\t.byte\n"); while (1) { r = next_token(ctx);

@@ -609,7 +609,7 @@ {

int sym_idx = find_symbol(token); if (sym_idx != -1 && symbols[sym_idx].type == SYMBOL_TYPE_MACRO) { - xyw_dbg("Macro in .byte:\t%s -> %s\n", token, symbols[sym_idx].contents); + XYW_DBG("Macro in .byte:\t%s -> %s\n", token, symbols[sym_idx].contents); // Copy macro contents into token buffer, skipping leading whitespace const char *contents = symbols[sym_idx].contents; while (*contents == ' ' || *contents == '\t')

@@ -656,7 +656,7 @@ if (process_symbol(ctx) != 0)

{ return -1; } - xyw_dbg("Directive:\t.macro %s\n", token); + XYW_DBG("Directive:\t.macro %s\n", token); char c; char contents[DIRECTIVE_CONTENT_MAX_LENGTH]; int length = 0;

@@ -1090,7 +1090,7 @@ fclose(fp);

return -1; } // Patch the data at the reference address with the label address - xyw_dbg("Patch:\t\t%s -> $%04X @ $%04X\n", defsym->name, defsym->address, refsym->address); + XYW_DBG("Patch:\t\t%s -> $%04X @ $%04X\n", defsym->name, defsym->address, refsym->address); XYW_POKEW(&data[refsym->address], defsym->address); } fwrite(data, 1, ptr, fp);
M xywrun.cxywrun.c

@@ -189,7 +189,7 @@ {

xyw_memory[SYSTEM_ERROR] = XYW_ERROR_STACK_OVERFLOW; return; } - xyw_dbg(" => %02X\n", val); + XYW_DBG(" => %02X\n", val); xyw_memory[USER_STACK_START + (*u)++] = val; }

@@ -201,7 +201,7 @@ xyw_memory[SYSTEM_ERROR] = XYW_ERROR_STACK_OVERFLOW;

return; } writew(USER_STACK_START + *u, val); - xyw_dbg(" => %04X\n", val); + XYW_DBG(" => %04X\n", val); (*u) += 2; }

@@ -329,7 +329,7 @@ xyw_word on_error_handler = XYW_PEEKW(&xyw_memory[SYSTEM_ON_ERROR]);

// If an error handler is set, jump to it if (on_error_handler != 0) { - xyw_dbg("Error occurred: %02X, jumping to error handler at %04X\n", xyw_memory[SYSTEM_ERROR], on_error_handler); + XYW_DBG("Error occurred: %02X, jumping to error handler at %04X\n", xyw_memory[SYSTEM_ERROR], on_error_handler); // Enter error state xyw_memory[SYSTEM_STATE] |= SYSTEM_STATE_ERROR; error_handler_entry_s = *s; // Record stack depth before pushing return address

@@ -348,18 +348,18 @@ if (on_timer_handler != 0)

{ if (readb(CLOCK_ON_TIMER_ELAPSED)) { - xyw_dbg("Timer elapsed, jumping to handler at %04X\n", on_timer_handler); + XYW_DBG("Timer elapsed, jumping to handler at %04X\n", on_timer_handler); xyw_eval(on_timer_handler); } } // Process terminal arguments if not already done static int argument_processing_active = 0; - if (!xyw_arguments_processed && !argument_processing_active && XYW_PEEKW(&xyw_memory[TERMINAL_ON_ARGUMENT]) && !(system_error_state())) + if (!xyw_argv_processed && !argument_processing_active && XYW_PEEKW(&xyw_memory[TERMINAL_ON_ARGUMENT]) && !(system_error_state())) { argument_processing_active = 1; // Prevent re-entry for (int i = 1; i < xyw_argc; i++) { - xyw_dbg("Processing argument %d of %d: %s\n", i, xyw_argc, xyw_argv[i]); + XYW_DBG("Processing argument %d of %d: %s\n", i, xyw_argc, xyw_argv[i]); const char *arg = xyw_argv[i]; for (size_t j = 0; arg[j] != '\0'; j++) {

@@ -371,7 +371,7 @@ writeb(TERMINAL_INPUT, XYW_ARGUMENT_SEPARATOR);

} } writeb(TERMINAL_INPUT, XYW_END_OF_ARGUMENTS); - xyw_arguments_processed = 1; + xyw_argv_processed = 1; argument_processing_active = 0; }

@@ -390,7 +390,7 @@ }

while ((system_running_state()) && *pc < SYSTEM_MEMORY_START) { process_events(); - xyw_dbg(" -- PC: %04X -> %02X (%s) [U:%02X|S:%02X|X:%02X|Y:%02X|XW:%04X|YW:%04X]\n", *pc, xyw_memory[*pc], xyw_instructions[xyw_memory[*pc] & 0x1F], *u, *s, *x, *y, *xw, *yw); + XYW_DBG(" -- PC: %04X -> %02X (%s) [U:%02X|S:%02X|X:%02X|Y:%02X|XW:%04X|YW:%04X]\n", *pc, xyw_memory[*pc], xyw_instructions[xyw_memory[*pc] & 0x1F], *u, *s, *x, *y, *xw, *yw); switch (xyw_memory[*pc]) { // clang-format off

@@ -470,7 +470,7 @@ fprintf(stderr, "Error - Could not read file contents [%s]\n", input);

fclose(fp); return -1; } - xyw_dbg("Loaded %zu bytes into memory\n", bytes_read); + XYW_DBG("Loaded %zu bytes into memory\n", bytes_read); fclose(fp); xyw_memory[SYSTEM_STATE] |= SYSTEM_STATE_RUNNING; // Initialize devices

@@ -493,7 +493,7 @@ xyw_word on_timer_handler = XYW_PEEKW(&xyw_memory[CLOCK_ON_TIMER_ELAPSED]);

if (on_keypress_handler) { - xyw_dbg("terminal.on_keypress handler set to %04X, entering input loop\n", on_keypress_handler); + XYW_DBG("terminal.on_keypress handler set to %04X, entering input loop\n", on_keypress_handler); while (system_running_state() || system_waiting_state()) { xyw_memory[SYSTEM_STATE] |= SYSTEM_STATE_WAITING;

@@ -509,14 +509,14 @@ }

} else if (on_timer_handler) { - xyw_dbg("clock.on_timer_elapsed handler set to %04X, entering timer loop\n", on_timer_handler); + XYW_DBG("clock.on_timer_elapsed handler set to %04X, entering timer loop\n", on_timer_handler); while (system_running_state() || system_waiting_state()) { xyw_memory[SYSTEM_STATE] |= SYSTEM_STATE_WAITING; if (readb(CLOCK_ON_TIMER_ELAPSED)) { xyw_memory[SYSTEM_STATE] |= SYSTEM_STATE_RUNNING; - xyw_dbg("Timer elapsed, calling handler at %04X\n", on_timer_handler); + XYW_DBG("Timer elapsed, calling handler at %04X\n", on_timer_handler); xyw_eval(on_timer_handler); // Refresh handler in case it was changed on_timer_handler = XYW_PEEKW(&xyw_memory[CLOCK_ON_TIMER_ELAPSED]);