forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

PS2 SDL Timer

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> Patch Submissions
View previous topic :: View next topic  
Author Message
protomank



Joined: 18 Dec 2008
Posts: 64
Location: Porto Alegre, RS, Brazil

PostPosted: Sat Feb 20, 2010 2:21 am    Post subject: PS2 SDL Timer Reply with quote

Hello. The current implementation of SDL timers and SDL_Delay is wrong, and do not work. Based in the work of shawn_t (link), I've made a very simple version of timers that still need some work (please take time to review it at will), but is already much better than having a non-working function.

Problems: time is not perfect yet, but close.
TODO List: Add support to multiple timers using threads as in the original SDL, fix the never implemented SDL_SYS_StartTimer.

I do not expect this patch to be submited, I just want people to help me out and point blockers that need to be fixed before commit :)

EDIT: forgot to include the diff:


Left file: /arquivos/programas/devel/ps2/sdl/src/timer/ps2sdk/SDL_systimer.c
Right file: /arquivos/programas/devel/ps2/sdl/src/timer/ps2sdk/SDL_systimer.c.original
1c1
< /*
---
> /*
29,31d28
< #include <tamtypes.h>
< #include <kernel.h>
< #include <debug.h>
44,48c41,44
< // =====================
< // Static Timer Variable
< // =====================
< static int s_tnInterruptID = -1;
< static u64 s_tnInterruptCount = 0;
---
> #define INTC_TIM1 10
> #define T1_COUNT (volatile u32 *)0x10000800
> #define T1_MODE (volatile u32 *)0x10000810
> #define T1_COMP (volatile u32 *)0x10000820
50d45
<
56,200d50
<
<
<
< // ================================================
< // Defines and Enumerations for timer related tasks
< // ================================================
< #define T0_COUNT ((volatile unsigned long*)0x10000000)
< #define T0_MODE ((volatile unsigned long*)0x10000010)
< #define T0_COMP ((volatile unsigned long*)0x10000020)
< #define T0_HOLD ((volatile unsigned long*)0x10000030)
<
< #define T1_COUNT ((volatile unsigned long*)0x10000800)
< #define T1_MODE ((volatile unsigned long*)0x10000810)
< #define T1_COMP ((volatile unsigned long*)0x10000820)
< #define T1_HOLD ((volatile unsigned long*)0x10000830)
<
< // Note! T2 and T3 don't have a Tn_HOLD register!
< // ----------------------------------------------
< #define T2_COUNT ((volatile unsigned long*)0x10001000)
< #define T2_MODE ((volatile unsigned long*)0x10001010)
< #define T2_COMP ((volatile unsigned long*)0x10001020)
<
< #define T3_COUNT ((volatile unsigned long*)0x10001800)
< #define T3_MODE ((volatile unsigned long*)0x10001810)
< #define T3_COMP ((volatile unsigned long*)0x10001820)
<
< #define Tn_MODE(CLKS,GATE,GATS,GATM,ZRET,CUE,CMPE,OVFE,EQUF,OVFF) \
< (u32)((u32)(CLKS) | ((u32)(GATE) << 2) | \
< ((u32)(GATS) << 3) | ((u32)(GATM) << 4) | \
< ((u32)(ZRET) << 6) | ((u32)(CUE) << 7) | \
< ((u32)(CMPE) << 8) | ((u32)(OVFE) << 9) | \
< ((u32)(EQUF) << 10) | ((u32)(OVFF) << 11))
<
< #define kBUSCLK (147456000)
< #define kBUSCLKBY16 (kBUSCLK / 16)
< #define kBUSCLKBY256 (kBUSCLK / 256)
< #define kHBLNK_NTSC (15734)
< #define kHBLNK_PAL (15625)
< #define kHBLNK_DTV480p (31469)
< #define kHBLNK_DTV1080i (33750)
<
< // =======================
< // Time Interrupt Callback
< // =======================
< int tnTimeInterrupt(int ca) {
< s_tnInterruptCount++;
< // A write to the overflow flag will clear the overflow flag
< // ---------------------------------------------------------
< *T1_MODE |= (1 << 11);
< return -1;
< }
<
< // ==============
< // Time functions
< // ==============
< void tnTimeInit(void) {
< // ============================================================
< // I am using 1/256 of the BUSCLK below in the Tn_MODE register
< // which means that the timer will count at a rate of:
< // 147,456,000 / 256 = 576,000 Hz
< // This implies that the accuracy of this timer is:
< // 1 / 576,000 = 0.0000017361 seconds (~1.74 usec!)
< // The Tn_COUNT registers are 16 bit and overflow in:
< // 1 << 16 = 65536 seconds
< // This implies that our timer will overflow in:
< // 65536 / 576,000 = 0.1138 seconds
< // I use an interrupt to recognize this overflow and increment
< // the <s_tnInterruptCount> variable so I can easily compute
< // the total time. This results in a very accurate timer that
< // is also very efficient. It is possible to have an even more
< // accurate timer by modifying the Tn_MODE, but at the expense
< // of having to call the overflow interrupt more frequently.
< // For example, if you wanted to use 1/16 of the BUSCLK, the
< // timer would count at a rate of:
< // 147,456,000 / 16 = 9,216,000 Hz
< // which implies an accuracy of:
< // 1 / 9,216,000 = 0.0000001085 seconds (0.11 usec!)
< // However, the timer will overflow in:
< // 65536 / 9,216,000 = 0.0071 seconds (7.1 msec)
< // meaning, the interrupt would be called more then 140 times a
< // second. For my purposes the accuracy of ~1.74 usec is fine!
< // ============================================================
<
< // Disable T1_MODE
< // ---------------
< *T1_MODE = 0x0000;
<
< // Initialize the overflow interrupt handler.
< // -----------------------------------------
< s_tnInterruptID = AddIntcHandler(kINTC_TIMER1, tnTimeInterrupt, 0);
< EnableIntc(kINTC_TIMER1);
<
< // Initialize the timer registers
< // CLKS: 0x02 - 1/256 of the BUSCLK (0x01 is 1/16th)
< // CUE: 0x01 - Start/Restart the counting
< // OVFE: 0x01 - An interrupt is generated when an overflow occurs
< // --------------------------------------------------------------
< *T1_COUNT = 0;
< *T1_MODE = Tn_MODE(0x02, 0, 0, 0, 0, 0x01, 0, 0x01, 0, 0);
<
< s_tnInterruptCount = 0;
< }
<
< u64 tnTime(void) {
< u64 t;
<
< // Tn_COUNT is 16 bit precision. Therefore, each
< // <s_tnInterruptCount> is 65536 ticks
< // ---------------------------------------------
< t = *T1_COUNT + (s_tnInterruptCount << 16);
<
< t = t * 1000000 / kBUSCLKBY256;
<
< return t;
< }
<
< void tnResetTimer(void) {
< s_tnInterruptCount = 0;
< }
<
< void tnTimeFini(void) {
< // Stop the timer
< // --------------
< *T1_MODE = 0x0000;
<
< // Disable the interrupt
< // ---------------------
< if (s_tnInterruptID >= 0)
< {
< DisableIntc(kINTC_TIMER1);
< RemoveIntcHandler(kINTC_TIMER1, s_tnInterruptID);
< s_tnInterruptID = -1;
< }
< s_tnInterruptCount = 0;
< }
<
< #define ONE_SECOND 1356155
<
< void wait_mseconds(double mseconds)
< {
< tnResetTimer();
< int TimeCheck = (mseconds*ONE_SECOND/1000); /* Relative Conversion of a Second to a Usec */
< while (tnTime() < TimeCheck);
< }
<
222,223c72,122
< void SDL_Delay(Uint32 ms) {
< wait_mseconds(ms);
---
> void SDL_Delay(Uint32 ms)
> {
> int i;
>
> if (nsleeping_threads >= MAX_SLEEPING_THREADS)
> {
> fprintf(stderr, "too many threads are sleeping at SDL_Delay (current thread %d)\n", GetThreadId());
> return;
> }
>
> /* in theory, a locking mechanism is required here. but since
> * nothing happens if interrupt handler wakes up an already
> * running thread, I chose not to use one.
> */
>
> i = nsleeping_threads;
> nsleeping_threads++;
>
> sleeping_threads[i] = GetThreadId();
>
> while (ms > 0)
> {
> SleepThread();
> ms--;
> }
>
> nsleeping_threads--;
> sleeping_threads[i] = sleeping_threads[nsleeping_threads];
> sleeping_threads[nsleeping_threads] = -1;
> }
>
> static int ms_handler(int ca)
> {
> int i;
>
> ticks++;
>
> for (i=0; i<nsleeping_threads; i++)
> {
> if (sleeping_threads[i] >= 0)
> {
> iWakeupThread(sleeping_threads[i]);
> }
> }
>
> /* reset counter */
> *T1_COUNT = 0;
> /* reset interrupt */
> *T1_MODE |= (1 << 10);
> __asm__ volatile("sync.l; ei");
> return 0;
227,229c126,138
< int SDL_SYS_TimerInit(void) {
< tnTimeInit();
< return 0;
---
> int SDL_SYS_TimerInit(void)
> {
> printf("initializing timer..\n");
>
> tim1_handler_id = AddIntcHandler(INTC_TIM1, ms_handler, 0);
> EnableIntc(INTC_TIM1);
>
> *T1_COUNT = 0;
> *T1_COMP = 586; /* 150MHZ / 256 / 1000 */
> *T1_MODE = 2 | (0<<2) | (0<<6) | (1<<7) | (1<<8);
>
> printf("timer init ended okay\n");
> return 0;
232,233c141,149
< void SDL_SYS_TimerQuit(void) {
< tnTimeFini();
---
> void SDL_SYS_TimerQuit(void)
> {
> DisableIntc(INTC_TIM1);
>
> if (tim1_handler_id >= 0)
> {
> RemoveIntcHandler(INTC_TIM1, tim1_handler_id);
> tim1_handler_id = -1;
> }
236c152,153
< int SDL_SYS_StartTimer(void) {
---
> int SDL_SYS_StartTimer(void)
> {
Back to top
View user's profile Send private message Visit poster's website
jimparis



Joined: 10 Jun 2005
Posts: 1179
Location: Boston

PostPosted: Thu Mar 11, 2010 3:01 am    Post subject: Reply with quote

Hi,
If you do get this into a form you'd like committed, please generate the patch with "diff -u" or "svn diff" and upload it somewhere, otherwise it's tricky for us to apply reliably.
Back to top
View user's profile Send private message
protomank



Joined: 18 Dec 2008
Posts: 64
Location: Porto Alegre, RS, Brazil

PostPosted: Thu Mar 11, 2010 3:06 am    Post subject: Reply with quote

Thanks. I'll fix the thread support and do it sometime. :)
Back to top
View user's profile Send private message Visit poster's website
cosmito



Joined: 04 Mar 2007
Posts: 314
Location: Portugal

PostPosted: Wed May 19, 2010 9:54 pm    Post subject: Reply with quote

Any news regarding your patch?

BTW, you have also some modifications regarding SDL init, right?
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> Patch Submissions All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group