Trying to wait for VSYNC that never happens crashes my game (C programming)

Get help from the community & developers with the X16 hardware if you can't find the solution elsewhere
Post Reply
RaichuBender
Posts: 5
Joined: Mon Jun 14, 2021 9:17 pm

Trying to wait for VSYNC that never happens crashes my game (C programming)

Post by RaichuBender »


Heya,



I'm trying to wait for a VSYNC to occur, so the title screen of my game won't flicker.

However, when setting the VSYNC bit of the EIN-register, it appears ISR is never set. Am I missing something?

My code:

 


#define EIN (*(u8*)0x9F26)
#define ISR (*(u8*)0x9F27)

#define VSYNC() \
{   EIN |= 1;\
    
while( !(ISR & 1) );    }

/* ... */

static void show_choices(TITLE *ttl)
{
    u8 y
,hand_pos;

    
while (1)
    
{
        SET_TILE_STR
(12, 14,    "+--------------+", TITLE_COL_MENU);
        SET_TILE_STR
(12, 15,    "|              |", TITLE_COL_MENU);
        
for (= 0; y < ttl->num_options; y++)
        
{
            SET_TILE_STR
(12, y+16,"| -            |", TITLE_COL_MENU);
            SET_TILE_STR
(16, y+16,ttl->OPTIONS_STR[y], TITLE_COL_MENU);
        
}
        SET_TILE_STR
(12, y+16,  "|              |", TITLE_COL_MENU);
        SET_TILE_STR
(12, y+17,  "+--------------+", TITLE_COL_MENU);

        SET_TILE
(13, hand_pos+16, '>', TITLE_COL_BG);
        hand_pos 
= (hand_pos + 1) & 3;
        VSYNC
();
    
}
}



 


SET_TILE_STR and TILE_COL_*** are macros that deal with updating the tile maps, so they aren't important for this question. It's the VSYNC at the bottom that locks up the system...

EDIT: I realize this function is within a while-loop that never get escaped out of. However, that is intentional, as I'm still working on the title screen. The problem is that the VSYNC never occurs as far as the game is concerned. 

Elektron72
Posts: 137
Joined: Tue Jun 30, 2020 3:47 pm

Trying to wait for VSYNC that never happens crashes my game (C programming)

Post by Elektron72 »


When the VSYNC interrupt occurs, the system jumps through the vector located at $0314, which points to the kernal interrupt handler (unless the vector has been modified). This routine performs several functions (polling the keyboard, updating the system timer, etc.). Before returning, the routine clears the interrupt status in ISR to prevent the interrupt from immediately triggering again. To properly wait for VSYNC, you will need to modify the vector at $0314 to point to your own interrupt handler. A custom handler will likely set a value somewhere in memory indicating that an interrupt has occured, and then jump to the original handler.

RaichuBender
Posts: 5
Joined: Mon Jun 14, 2021 9:17 pm

Trying to wait for VSYNC that never happens crashes my game (C programming)

Post by RaichuBender »



3 hours ago, Elektron72 said:




When the VSYNC interrupt occurs, the system jumps through the vector located at $0314, which points to the kernal interrupt handler (unless the vector has been modified). This routine performs several functions (polling the keyboard, updating the system timer, etc.). Before returning, the routine clears the interrupt status in ISR to prevent the interrupt from immediately triggering again. To properly wait for VSYNC, you will need to modify the vector at $0314 to point to your own interrupt handler. A custom handler will likely set a value somewhere in memory indicating that an interrupt has occured, and then jump to the original handler.



Ah, that must be it. thank you!

It seems I'm misunderstanding the workings of the ISR register then. 

 

UPDATE:

I did it!

Here's a video of it VSYNC-ing after every BG line drawn: (PETSCII characters are placeholders for now.)





Can you guess where this placeholder BG is a reference to? ?

Greg King
Posts: 162
Joined: Wed Jul 08, 2020 1:14 pm

Trying to wait for VSYNC that never happens crashes my game (C programming)

Post by Greg King »


In order to do what you want, your program needs two things:


  1. It needs to know when the vertical blanking is happenning.


  2. It needs to keep control of the computer.


Your current code has number 1; but, number 1 can't work because it doesn't have number 2 (Kernal takes control and cancels number 1).

Your program can get number 2 by temporarily preventing the CPU from seeing interrupts.  The usual way in C code is to use a "SEI()" macro.  Then, your code waits for the VSYNC flag. After it sees that flag, your code updates the menu.  Then, it allows the CPU to notice interrupts again [a CLI() macro].  After that, your code gets player input, then possibly repeats the loop.  [Notice that VSYNC() is done at the beginning of the loop, not at the end.]

#define VSYNC() while (!(ISR & 1))

do {
  SEI
();
  VSYNC
();

 
// Redraw the new menu.
 
// And update the positions of "carots" and highlights.

  CLI
();
 
// Handle input from the player.
} while (!finished);

How your code gets the SEI() and CLI() macros depends on which C compiler you're using (your code looks like KickC).

RaichuBender
Posts: 5
Joined: Mon Jun 14, 2021 9:17 pm

Trying to wait for VSYNC that never happens crashes my game (C programming)

Post by RaichuBender »


Currently, I'm wrapping a check whether the VSYNC occurred around the interrupt handler, which in turn sets a `vsync` boolean to true if it has.

Will append the code of my implementation when I'm home in a bit, so you can give your input if you want ?

Also, I've always put the VSYNC delay at the end of any drawing loop. As there any benefit of putting it at the start? Most of my programming work so far has been in BASIC, so I might have been doing it in a not optimal way forever... 

User avatar
desertfish
Posts: 1096
Joined: Tue Aug 25, 2020 8:27 pm
Location: Netherlands

Trying to wait for VSYNC that never happens crashes my game (C programming)

Post by desertfish »


 


6 minutes ago, RaichuBender said:




the interrupt handler, which in turn sets a `vsync` boolean to true if it has.



So you already have an interrupt handler? so just do the vsync processing in there, why even wait for a vsync elsewhere?

RaichuBender
Posts: 5
Joined: Mon Jun 14, 2021 9:17 pm

Trying to wait for VSYNC that never happens crashes my game (C programming)

Post by RaichuBender »



24 minutes ago, desertfish said:




So you already have an interrupt handler? so just do the vsync processing in there, why even wait for a vsync elsewhere?



Simply because I want to have precise control over my code, including when it should wait for a VSYNC, and when tearing and flickering might be ok for speed's sake.

But I could probably move all the logic to the interrupt handler as you suggest, and keep the control by specifying when the routine should be skipped or not based on macros in my loops. 

I guess the best way to explain what I want to be able to achieve is screen fill/wipe animations like the fancy Pokémon battle start animations that fill the screen with tiles in a maze-like pattern for example. Having precise control of interrupts without having to retrofit everything in a large event is the best approach I find.

Post Reply