|
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
View previous topic :: View next topic |
Author |
Message |
protomank
Joined: 18 Dec 2008 Posts: 64 Location: Porto Alegre, RS, Brazil
|
Posted: Sat Feb 20, 2010 2:21 am Post subject: PS2 SDL Timer |
|
|
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 |
|
|
jimparis
Joined: 10 Jun 2005 Posts: 1179 Location: Boston
|
Posted: Thu Mar 11, 2010 3:01 am Post subject: |
|
|
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 |
|
|
protomank
Joined: 18 Dec 2008 Posts: 64 Location: Porto Alegre, RS, Brazil
|
Posted: Thu Mar 11, 2010 3:06 am Post subject: |
|
|
Thanks. I'll fix the thread support and do it sometime. :) |
|
Back to top |
|
|
cosmito
Joined: 04 Mar 2007 Posts: 314 Location: Portugal
|
Posted: Wed May 19, 2010 9:54 pm Post subject: |
|
|
Any news regarding your patch?
BTW, you have also some modifications regarding SDL init, right? |
|
Back to top |
|
|
|
|
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
|