Added tick to device contract; refactored error handling.
h3rald h3rald@h3rald.com
Sun, 26 Jul 2026 15:43:09 +0200
4 files changed,
61 insertions(+),
44 deletions(-)
M
devices/system.c
→
devices/system.c
@@ -7,12 +7,22 @@ #define SYSTEM_STATE 0x00
#define SYSTEM_ERROR 0x01 #define SYSTEM_PAGE 0x02 #define SYSTEM_RANDOM 0x03 +#define SYSTEM_ON_ERROR 0x04 #define SYSTEM_IMAGE_EXEC 0x06 +#define SYSTEM_STATE_RUNNING 0x01 +#define SYSTEM_STATE_ERROR 0x80 + +#define XYW_ERROR_NONE 0 + +/// Error handler tracking (accessible by xywrun.c for snapshot/reset) +xyw_byte error_handler_entry_s = 0; + void system_setup(xyw_byte *data) { (void)data; srand(time(NULL)); + error_handler_entry_s = 0; } xyw_byte system_input(xyw_byte *data, xyw_byte addr, xyw_byte *error)@@ -33,3 +43,34 @@ if (target != 0)
xyw_request_exec(target); } } + +void system_tick(xyw_byte *data) +{ + // Check if returning from error handler (after RTS popped the frame) + if ((data[SYSTEM_STATE] & SYSTEM_STATE_ERROR) && + error_handler_entry_s != 0 && + xyw_vm_get_system_depth() == error_handler_entry_s) + { + data[SYSTEM_STATE] &= ~SYSTEM_STATE_ERROR; + error_handler_entry_s = 0; + } + + // Check for new error condition + if (data[SYSTEM_ERROR] != XYW_ERROR_NONE && !(data[SYSTEM_STATE] & SYSTEM_STATE_ERROR)) + { + xyw_word on_error_handler = XYW_PEEKW(&data[SYSTEM_ON_ERROR]); + if (on_error_handler != 0) + { + XYW_DBG("Error occurred: %02X, jumping to error handler at %04X\n", data[SYSTEM_ERROR], on_error_handler); + data[SYSTEM_STATE] |= SYSTEM_STATE_ERROR; + error_handler_entry_s = xyw_vm_get_system_depth(); + xyw_vm_push_frame(*pc); + *pc = on_error_handler; + } + else + { + // No error handler: halt execution + data[SYSTEM_STATE] &= ~SYSTEM_STATE_RUNNING; + } + } +}
M
devices/system.h
→
devices/system.h
@@ -2,4 +2,8 @@ #include "../xyw.h"
void system_setup(xyw_byte *data); xyw_byte system_input(xyw_byte *data, xyw_byte addr, xyw_byte *error); -void system_output(xyw_byte *data, xyw_byte addr, xyw_byte *error);+void system_output(xyw_byte *data, xyw_byte addr, xyw_byte *error); +void system_tick(xyw_byte *data); + +/// Error handler stack depth tracking (saved/restored in snapshots) +extern xyw_byte error_handler_entry_s;
M
xyw.h
→
xyw.h
@@ -27,6 +27,7 @@ typedef void (*xyw_teardown)(xyw_byte *data);
typedef int (*xyw_poll)(xyw_byte *data); // returns: 1=dispatched, 0=inactive, -1=active but no event typedef void (*xyw_save)(xyw_byte *data, xyw_byte *state); typedef void (*xyw_restore)(xyw_byte *data, const xyw_byte *state); +typedef void (*xyw_tick)(xyw_byte *data); #define XYW_DEVICE_STATE_SIZE 64@@ -40,6 +41,7 @@ xyw_teardown teardown;
xyw_poll poll; xyw_save save; xyw_restore restore; + xyw_tick tick; } xyw_device; // Main Globals
M
xywrun.c
→
xywrun.c
@@ -26,7 +26,6 @@ #define SYSTEM_STATE 0xff00
#define SYSTEM_ERROR 0xff01 #define SYSTEM_PAGE 0xff02 #define SYSTEM_RANDOM 0xff03 -#define SYSTEM_ON_ERROR 0xff04 typedef enum {@@ -183,7 +182,6 @@ return return_addr;
} //// Internal VM state -xyw_byte error_handler_entry_s = 0; static int system_error_state() {@@ -378,42 +376,24 @@ //// Initialize devices
xyw_device xyw_devices[XYW_TOTAL_DEVICES] = { // System device - {&xyw_memory[0xff00], system_setup, system_input, system_output, 0, 0, 0, 0}, + {&xyw_memory[0xff00], system_setup, system_input, system_output, 0, 0, 0, 0, system_tick}, // Terminal device - {&xyw_memory[0xff10], terminal_init, terminal_input, terminal_output, terminal_teardown, terminal_poll, terminal_save, terminal_restore}, + {&xyw_memory[0xff10], terminal_init, terminal_input, terminal_output, terminal_teardown, terminal_poll, terminal_save, terminal_restore, 0}, // Clock device - {&xyw_memory[0xff20], clock_setup, clock_input, clock_output, 0, clock_poll, 0, 0}, + {&xyw_memory[0xff20], clock_setup, clock_input, clock_output, 0, clock_poll, 0, 0, 0}, // File device - {&xyw_memory[0xff30], file_setup, file_input, file_output, 0, 0, 0, 0}, + {&xyw_memory[0xff30], file_setup, file_input, file_output, 0, 0, 0, 0, 0}, // Beeper device - {&xyw_memory[0xff40], 0, beeper_input, beeper_output, beeper_teardown, 0, 0, 0}, + {&xyw_memory[0xff40], 0, beeper_input, beeper_output, beeper_teardown, 0, 0, 0, 0}, // ... }; // clang-format on -static int process_events() +static int has_poll_devices(void) { - // Error handling - if (xyw_memory[SYSTEM_ERROR] != XYW_ERROR_NONE && !system_error_state()) - { - 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); - // Enter error state - xyw_memory[SYSTEM_STATE] |= SYSTEM_STATE_ERROR; - error_handler_entry_s = s; // Record stack depth before pushing return address - ss_push_frame(*pc); - *pc = on_error_handler; - } - else - { - // No error handler: halt execution - xyw_memory[SYSTEM_STATE] &= ~SYSTEM_STATE_RUNNING; - return xyw_memory[SYSTEM_ERROR]; - } - } + for (int i = 0; i < XYW_TOTAL_DEVICES; i++) + if (xyw_devices[i].poll) + return 1; return 0; }@@ -600,14 +580,6 @@ restore_snapshot(&exec_stack[--exec_stack_depth]);
} } -static int has_poll_devices(void) -{ - for (int i = 0; i < XYW_TOTAL_DEVICES; i++) - if (xyw_devices[i].poll) - return 1; - return 0; -} - //// Main evaluation function - runs from current pc until BRK int xyw_eval(xyw_word start_pc) {@@ -663,7 +635,10 @@ }
break; // no parent -- genuinely done } - process_events(); + // Tick devices (error handling, etc.) + for (int i = 0; i < XYW_TOTAL_DEVICES; i++) + if (xyw_devices[i].tick) + xyw_devices[i].tick(xyw_devices[i].data); handle_exec_requests(); if (!system_running_state()) {@@ -724,11 +699,6 @@ /* JCN */ OPC_SR1(0x1D, , xyw_word addr = ADDR(ARG); xyw_byte cond = us_pop(); if (cond) { *pc = addr-1; });
/* JSR */ OPC_SR1(0x1E, xyw_word addr = ADDR(ARG), ss_push_frame(*pc+1); *pc = addr-1;); /* RTS */ case 0x1F: *pc = ss_pop_frame()-1; - // If returning from error handler, clear flag to allow re-trigger - if ((system_error_state()) && s == error_handler_entry_s) { - xyw_memory[SYSTEM_STATE] &= ~SYSTEM_STATE_ERROR; - error_handler_entry_s = 0; - } break; // clang-format on }