From 310804e26770f5db12a6ba5081eb682ae0283f4e Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Fri, 28 Aug 2026 23:19:53 -0400 Subject: [PATCH] Give Snake back the speed its comment promised, and present in step with the display Two things, one certain and one likely. THE CERTAIN ONE IS NOT THE WINDOW'S FAULT. Snake's pause loop said "at the emulated rate this is about an eighth of a second", and it was, when a cycle was one instruction. A cycle became one memory access, every loop in the machine got dearer, and this one silently doubled: the game has been running at half the speed it documents ever since, in a terminal as much as in a window. Measured rather than guessed - the inner loop is a DECA and a BNA, one byte and three, so four cycles a turn, and a whole run went from 3,848,610 cycles to 1,920,504 when the outer count came down from 256 to 122. Almost exactly half, which is what the arithmetic said it would be. That is the cost model change reaching a program nobody thought to re-measure. Worth looking for others: any loop tuned by eye before that change is running at half its intended speed. THE LIKELY ONE is the frame limiter. Without the vsync hint, Raylib sleeps towards sixty frames a second on its own clock, which beats against a display refreshing on its own - frames shown twice or skipped, and the machine handed an uneven number of cycles each time, since it takes its budget from the wall clock. The hint puts presentation in step with the screen. SetTargetFPS stays for a driver that ignores it. Snake is one byte bigger, because RSTB became INIB. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW --- Programs/CosmOS/Apps/Snake.asm | 17 ++++++++++++----- Source/Emulator/voyager.c | 8 +++++++- Tests/expected/cosmosRun.out | 2 +- Tests/expected/cosmosSlowDisk.out | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Programs/CosmOS/Apps/Snake.asm b/Programs/CosmOS/Apps/Snake.asm index 0078ff4..e7cb6b5 100644 --- a/Programs/CosmOS/Apps/Snake.asm +++ b/Programs/CosmOS/Apps/Snake.asm @@ -591,12 +591,19 @@ drawPut: ; ---- Waiting ---- ; -; There is no clock on this machine, so time is counted in instructions. At the emulated -; rate this is about an eighth of a second, which is a speed a person can play at. Running -; the emulator faster or slower moves it, and that is the honest answer: the machine has -; no way to know how long a second is and this program is not going to pretend it does. +; There is no clock on this machine, so time is counted in cycles. At the emulated rate this +; is about an eighth of a second, which is a speed a person can play at. Running the emulator +; faster or slower moves it, and that is the honest answer: the machine has no way to know +; how long a second is and this program is not going to pretend it does. +; +; THE COUNT USED TO BE 256 AND THE COMMENT USED TO SAY INSTRUCTIONS. When a cycle stopped +; being an instruction and became a memory access, every loop in the machine got dearer and +; this one silently doubled - the game has been running at half the speed it says ever since, +; in a terminal as much as in a window. The inner loop is a DECA and a BNA, one byte and +; three, so four cycles a turn: 122 times 256 times 4 is about 125,000, which is an eighth of +; a second at a megahertz. pause: - RSTB + INIB 0d122 pauseOuter: RSTA pauseInner: diff --git a/Source/Emulator/voyager.c b/Source/Emulator/voyager.c index f8d8c01..ec55093 100644 --- a/Source/Emulator/voyager.c +++ b/Source/Emulator/voyager.c @@ -242,7 +242,13 @@ int main(int argc, char *argv[]) { } else { // Resizable, because how big somebody wants a screen is not the machine's business. // The picture is rescaled to whatever the window becomes, in whole pixels. - SetConfigFlags(FLAG_WINDOW_RESIZABLE); + // + // And presented in step with the display. Without the hint the frame limiter sleeps + // towards sixty a second on its own clock, which beats against a screen refreshing on + // its own - some frames shown twice, some skipped, and the machine handed an uneven + // number of cycles each time because it takes them from the wall clock. The target + // stays as well, for a driver that ignores the hint. + SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_VSYNC_HINT); InitWindow(VIDEO_MAX_WIDTH * SCREEN_SCALE, VIDEO_MAX_HEIGHT * SCREEN_SCALE, "Segan Voyager"); SetTargetFPS(60); diff --git a/Tests/expected/cosmosRun.out b/Tests/expected/cosmosRun.out index ab141cf..c5e3c7e 100644 --- a/Tests/expected/cosmosRun.out +++ b/Tests/expected/cosmosRun.out @@ -3,7 +3,7 @@ CosmOS > greet.sbx 211 hello.sbx 53 Life.sbx 1396 -Snake.sbx 2163 +Snake.sbx 2164 Keys.sbx 664 Say.sbx 156 Break.sbx 149 diff --git a/Tests/expected/cosmosSlowDisk.out b/Tests/expected/cosmosSlowDisk.out index 0abfaff..c74d37d 100644 --- a/Tests/expected/cosmosSlowDisk.out +++ b/Tests/expected/cosmosSlowDisk.out @@ -2,7 +2,7 @@ CosmOS > greet.sbx 211 hello.sbx 53 Life.sbx 1396 -Snake.sbx 2163 +Snake.sbx 2164 Keys.sbx 664 Say.sbx 156 Break.sbx 149