all repos — xyw @ 1dda486594c70fa9398936c319086a694c076187

A minimal virtual machine and assembler for terminals.

Refactored clock device
h3rald h3rald@h3rald.com
Sun, 26 Jul 2026 15:23:46 +0200
commit

1dda486594c70fa9398936c319086a694c076187

parent

f0b38cab4d79943db10eb65ba5d7d7fa71b8629c

3 files changed, 36 insertions(+), 32 deletions(-)

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

@@ -81,6 +81,39 @@ return remaining_ticks;

#endif } +#define CLOCK_POLL_SLEEP_MS 100 + +int clock_poll(xyw_byte *data) +{ + xyw_word on_timer_handler = XYW_PEEKW(&data[CLOCK_ON_TIMER_ELAPSED]); + if (!on_timer_handler) + return 0; // no handler registered + + // Check if timer has elapsed (non-blocking) + clock_get_timer_value(); + if (clock_timer_elapsed_pending) + { + clock_timer_elapsed_pending = 0; + xyw_vm_set_running(1); + xyw_vm_push_frame(XYW_DEVICE_AREA_START); + *pc = on_timer_handler; + return 1; + } + + if (!clock_timer_active) + return 0; // no timer running + + // Timer is active but hasn't elapsed yet — sleep briefly to avoid busy loop. + // When terminal_poll is also active, it provides its own 100ms sleep via + // getch_timeout, so this sleep only matters for timer-only programs. +#ifdef _WIN32 + Sleep(CLOCK_POLL_SLEEP_MS); +#else + usleep((useconds_t)(CLOCK_POLL_SLEEP_MS * 1000)); +#endif + return -1; // active handler, no event yet +} + void clock_setup(xyw_byte *data) { (void)data;
M devices/clock.hdevices/clock.h

@@ -3,3 +3,4 @@

void clock_setup(xyw_byte *data); xyw_byte clock_input(xyw_byte *data, xyw_byte addr, xyw_byte *error); void clock_output(xyw_byte *data, xyw_byte addr, xyw_byte *error); +int clock_poll(xyw_byte *data);
M xywrun.cxywrun.c

@@ -391,7 +391,7 @@ {&xyw_memory[0xff00], system_setup, system_input, system_output, 0, 0, 0, 0},

// Terminal device {&xyw_memory[0xff10], terminal_init, terminal_input, terminal_output, terminal_teardown, terminal_poll, terminal_save, terminal_restore}, // Clock device - {&xyw_memory[0xff20], clock_setup, clock_input, clock_output, 0, 0, 0, 0}, + {&xyw_memory[0xff20], clock_setup, clock_input, clock_output, 0, clock_poll, 0, 0}, // File device {&xyw_memory[0xff30], file_setup, file_input, file_output, 0, 0, 0, 0}, // Beeper device

@@ -611,8 +611,7 @@ }

//// Event dispatch (WAITING state) -// Addresses of all event handler slots — add new handlers here. -// Both has_event_handlers() and feed_next_event() stay in sync via this table. +// Addresses of event handler slots — used by HLT to decide whether to enter WAITING. static const xyw_word event_handler_addrs[] = { TERMINAL_ON_ARGUMENT, TERMINAL_ON_KEYPRESS,

@@ -628,32 +627,6 @@ return 1;

return 0; } -// Feed legacy event (timer only — terminal is handled by terminal_poll). -// Returns 1 if an event was dispatched, 0 if no more events. -static int feed_next_event(void) -{ - xyw_word on_keypress_handler = XYW_PEEKW(&xyw_memory[TERMINAL_ON_KEYPRESS]); - xyw_word on_timer_handler = XYW_PEEKW(&xyw_memory[CLOCK_ON_TIMER_ELAPSED]); - - if (on_timer_handler) - { - // If keypress handler is also active, do non-blocking check - // (terminal_poll provides the sleep via getch_timeout) - int elapsed = on_keypress_handler - ? (readw(CLOCK_TIMER) == 0 && readb(CLOCK_ON_TIMER_ELAPSED)) - : readb(CLOCK_ON_TIMER_ELAPSED); // blocking: timer-only program - if (elapsed) - { - xyw_memory[SYSTEM_STATE] |= SYSTEM_STATE_RUNNING; - ss_push_frame(DEVICE_AREA_START); - *pc = on_timer_handler; - return 1; - } - } - - return 0; -} - //// Main evaluation function - runs from current pc until BRK int xyw_eval(xyw_word start_pc) {

@@ -693,9 +666,6 @@ if (r > 0) { dispatched = 1; break; }

if (r < 0) active = 1; } if (dispatched) break; - // Legacy: timer handling (will be moved to clock_poll in step 4) - if (feed_next_event()) { dispatched = 1; break; } - // If no device is actively waiting, exit if (!active) break; } if (dispatched)