Page 1 of 1

How do I "tick" my simulation every 17 milliseconds without a realtime clock?

Posted: Fri Jul 12, 2024 6:21 pm
by nulcow
My program's simulation runs at a fixed rate of 60 times per second (16.67 milliseconds per tick, later changed to 17 milliseconds due to a lack of floating point number support). On a system with a real-time clock, this worked perfectly fine, using the following code:

Code: Select all

while (game->isRunning) {
    if (game->timeLastTicked + CC_TICKRATE < cc_util_ctms()) {
        cc_tickGame(game);
        //printf("[CCCore] Current tick: %d\n", game->tick);
    }
}
cc_tickGame() is the function which runs the simulation, while cc_util_ctms() simply returns the current time in milliseconds. game->timeLastTicked is the last time, in milliseconds, when cc_tickGame() was called.
The issue is that this code relies on the real-time clock functionality from the standard library header sys/time.h, which works fine under Unix (and other POSIX-compliant systems), but either doesn't exist or works very differently under cc65 on a 6502 system.

I tried a version of this using sleep() from cc65's unistd.h, but that just doesn't work how I need it to. Is there a better way to define a fixed tick rate for my game?

Re: How do I "tick" my simulation every 17 milliseconds without a realtime clock?

Posted: Fri Jul 12, 2024 7:36 pm
by mgkaiser
You could hook the vertical refresh interrupt which will run 60 times per second.

Re: How do I "tick" my simulation every 17 milliseconds without a realtime clock?

Posted: Fri Jul 12, 2024 9:35 pm
by TomXP411
There is now a SLEEP command in BASIC. This causes the system to pause until the next interrupt (or n interrupts.)

In the X16-ROM repo, check out sleep: in x16additions.s and the entire bannex/sleep_cont.s file.

https://github.com/X16Community/x16-rom

You might also be able to use the WAI instruction to stop until the next interrupt. Since the most common source of an interrupt is the Jiffy timer, this would generally cause your code to pause until the Jiffy timer triggers, every 1/60 second.

Re: How do I "tick" my simulation every 17 milliseconds without a realtime clock?

Posted: Mon Jul 15, 2024 12:29 am
by cosmicr
If you're using C with CC65, you may have trouble using the wai 65c02 instruction in inline assembly (the compiler seems to not recognise it). You could include an assembler routine in a separate file like this though:

Code: Select all

; 65C02 instruction set
.pc02

; Commander X16 definitions
.include "cx16.inc"

; Switch to code segment
.code

; wait function - system clock ticks at 60Hz
.export _asm_wait_for_refresh
.proc _asm_wait_for_refresh
    wai	; wait for next interrupt
.endproc; end of _asm_wait_for_refresh
or alternatively if you don't want to use the `wai` instruction:

Code: Select all

; 65C02 instruction set
.pc02

; Commander X16 definitions
.include "cx16.inc"
.include "cbm_kernal.inc"

; Switch to code segment
.code

; wait function - system clock ticks at 60Hz
.export _asm_wait_for_refresh
.proc _asm_wait_for_refresh
    time = $40 ; zero page address - change as necessary

    jsr RDTIME ; call the kernal function $FFDE
    sta time; store the value in the start variable

    loop:
        jsr RDTIME ; call the kernal function again
        cmp time ; compare the value to the start variable
        beq loop ; if they are equal, loop again
.endproc ; end of _asm_wait_for_refresh
or the above could be done with inline assembly too:

Code: Select all

static uint8_t time;
__asm__("jsr RDTIME");
__asm__("sta %v", time);
loop:
__asm__("jsr RDTIME");
__asm__("cmp %v", time);
__asm__("beq %g", loop);
I haven't tested it.