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

All aspects of programming on the Commander X16.
Post Reply
nulcow
Posts: 7
Joined: Mon Oct 23, 2023 11:48 pm

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

Post 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?
nulcow, software developer and computer artist.
mgkaiser
Posts: 60
Joined: Sat Dec 02, 2023 6:49 pm

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

Post by mgkaiser »

You could hook the vertical refresh interrupt which will run 60 times per second.
TomXP411
Posts: 1783
Joined: Tue May 19, 2020 8:49 pm

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

Post 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.
cosmicr
Posts: 34
Joined: Tue Nov 14, 2023 4:29 am

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

Post 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.
Post Reply