Making delay-tick functions

vbt

Staff member
Thanks to CyberWarriorX advice, I started getTick and getDelay functions using a FRT timer. The functions are quoted below. I have tested only on emu but on them I got different problems :


- On Girigiri it stays locked

- On Yabause, it starts but get stucked later

- On Satourne, I got an opcode problem


Is there something I missed to setup the timer? Could I reach an overflow ? something else ?



Code:
static Uint32 count=0;

Uint16 previouscount=0;

Uint16 multip=0;


void InitTimer()

{

	TIM_FRT_INIT(TIM_CKS_32);

	TIM_FRT_SET_16(0);

}


Uint32 GetTicks(void)

{

	Uint16 count1 = TIM_FRT_GET_16();

	if (count1<previouscount)

		multip++;

	count=((multip<<15)+count1);


	previouscount=count1;

	return TIM_FRT_CNT_TO_MCR(count)/1000;

}

void Delay(int delay)

{

	Uint16 cnt_delay;

	cnt_delay= TIM_FRT_MCR_TO_CNT(delay);


	TIM_FRT_DELAY_16(cnt_delay);

}
 
At least the TIM_FRT_DELAY_16 macro is questionable, at it compares the FRC value directly to the parameter value. A small clock divider or interrupts can cause the comparison to fail, leading to too long waits or in the extreme case a never-ending loop. The proper way would be to use the output compare registers.


The FTCSR register has an overflow flag, which is more reliable than comparing values. Of course neither way will detect multiple overflows, for that you have to use the overflow interrupt.


Note that the TIM_FRT_DELAY_16 macro will reset the FRC to 0, so your GetTicks routine will not count at a steady rate if you also use delays.


(Also, since the timer is 16-bit, shouldn't multip be shifted by 16 bits?)
 
antime said:
At least the TIM_FRT_DELAY_16 macro is questionable, at it compares the FRC value directly to the parameter value. A small clock divider or interrupts can cause the comparison to fail, leading to too long waits or in the extreme case a never-ending loop. The proper way would be to use the output compare registers.

It looks to be my problem.

The FTCSR register has an overflow flag, which is more reliable than comparing values. Of course neither way will detect multiple overflows, for that you have to use the overflow interrupt.

I don't know how to do that :(

Note that the TIM_FRT_DELAY_16 macro will reset the FRC to 0, so your GetTicks routine will not count at a steady rate if you also use delays.

I was lazy, I did a quick fix, I've removed the content of the Delay function. It fixed the problem on Girigiri and i can play without any lock. Maybe it's time to burn a CD.

(Also, since the timer is 16-bit, shouldn't multip be shifted by 16 bits?)

Maybe :) I had some problems to get correct wait on emus and tried this. I doubled also the delay.
 
I've tested today on ssf 0.10 and Madroms did on previous ssf, it crashes at the same time on ssf and yabause. So GetTicks really needs to be improved.
 
I'd like to pull out a different option for implementing it.

Depending on the game you are porting (I assume this topic belongs to porting), you can fake the behaviour just so that it works for the game. For example, GemDropX advances the game time by checking current time via SDL_GetTicks(), then compares the time consumed compared to the previous check one frame before and finally it causes a delay for the remaining time until the next regular frame using SDL_Delay().

For this example it's sufficient to keep track of a frame counter yourself and to convert that framecounter into milliseconds, whenever SDL_GetTicks() is called. In SDL_Delay(), I perform a slSynch() for every 33ms delay (30FPS).

This approximation works for me, though it may need some fine tuning in order to mimic the gameplay behaviour correctly.
 
RockinB said:
I'd like to pull out a different option for implementing it.


Depending on the game you are porting (I assume this topic belongs to porting),

Yes, exactly.

you can fake the behaviour just so that it works for the game.

No, I wanted to have a right behavior for any game.

For example, GemDropX advances the game time by checking current time via SDL_GetTicks(), then compares the time consumed compared to the previous check one frame before and finally it causes a delay for the remaining time until the next regular frame using SDL_Delay().


For this example it's sufficient to keep track of a frame counter yourself and to convert that framecounter into milliseconds, whenever SDL_GetTicks() is called. In SDL_Delay(), I perform a slSynch() for every 33ms delay (30FPS).


This approximation works for me, though it may need some fine tuning in order to mimic the gameplay behaviour correctly.

I tried a simple counter and the result was it continued to crash !!!!

I've continued to search why I have these issues and it happened to be something like soundram was full or something like that. In fact, I've replaced all WAV by PCM, common sounds are loaded in Saturn memory (420kb) and background sound in high work ram (from 150kb to 780kb).

I call now slSndFlush during the game and it solve the problem on Yabause. I move to another task :)
 
Back
Top