/* 30/8/01 Psx timer functions for timing code sections. I've written the info I've learned from testing here as I'll soon forget it, hopefully it's not too inaccurate. There are 3 root counters available for timing, 0, 1 and 2. Root counters 0 and 2 appear to be identical separate timers updated every CPU clock tick, 33 million times a second (0.00000003sec). This disagrees with the documentation on root counter 2 which which states it's updated every 8 clock ticks, but I've not found this to be the case. Root counter 1 is the hsync scanline counter most often used for code timing. To work out how often it's updated, in PAL there are 312 scanlines at 50 frames per second so root counter 1 increases every 1sec / 50 frames / 312scanlines = 0.00006410sec. In NTSC 1 / 60 / 262 = 0.00006361sec. Using these figures, it works out that in PAL there are approximately 6410 / 3 = 2136 ticks of the 0 and 2 root counters for one of the hsync counter. In NTSC 6361 / 3 = 2120. The root counters are stored as 16bit values, for 0 and 2 these wrap around very quickly, about once every 31 hsyncs. In testing the average number of ticks between hsync increments was around 2160, I was using the functions below so there was some overhead, running in a critical section helped to steady the root counters. The basic idea of the functions is to be able to time any piece of code and return the the time taken in clock ticks and scanline hsyncs. At the moment the functions return the number of ticks, the total non-wrapped number of ticks, the number of hsyncs and the percentage of frame time used. The total tick value is calculated by adding on 65536 to the tick value for every 31 hsyncs that have passed. Because the root counter doesn't wrap around at exactly every 31 hsyncs, the counter is not totally accurate around 31, 62, 93 etc hsyncs. To use the timer functions, call InitTimer at the start of your program, and put StartTimer and GetTimer (or StartTimer2 & GetTimer2) around your code. GetTimer returns the total number of clock ticks since the StartTimer call. This value as well as the wrapped tick total, hsync count and percentage are stored in the timer structure, you'll need to add extern S_TIME timer; to your program to access it, same goes for timer2. As an example of the return values, the following is a timed for loop executed in PAL: StartTimer(); for(i = 0; i < 40000; i++); GetTimer(); timer.time 29074 16bit root counter value, wrapped around 2 times timer.total 160146 32bit value of root counter, 29074 + (hsync / 31 * 65536) timer.hsync 74 scanline counter timer.percent 23 frame time used */ /* includes */ #include #include "timer.h" /* globals */ int HSyncsPerFrame; int HSyncStart, HSyncStart2, HSync, HSync2; S_TIME timer; S_TIME timer2; /* Get the scanlines per frame value for video mode, value used to work out percentage of frame time used */ void InitTimer(void) { if(GetVideoMode() == MODE_PAL) HSyncsPerFrame = 312; else HSyncsPerFrame = 262; } /* Get current hsync counter value, start root counter 2 */ void StartTimer(void) { HSyncStart = GetRCnt(1); /* get rc1's current value */ ResetRCnt(2); /* reset rc2 to zero */ StartRCnt(2); } /* Return number of clock ticks since StartTimer was called, the time passed in hsyncs and the percentage of frame time used are also stored in the timer structure */ int GetTimer(void) { timer.time = GetRCnt(2); /* get current value */ HSync = GetRCnt(1) - HSyncStart; /* get difference */ if(HSync < 0) /* if less than zero, timer wrapped around */ HSync += CNTR_MAX; timer.hsync = HSync; /* time in hsyncs */ timer.percent = HSync * 100 / HSyncsPerFrame; /* percentage of frame time */ /* rc2 timer wraps around every 30~31 hsyncs approx, calc total rc2 ticks */ HSync /= 31; timer.total = timer.time + (HSync << 16); /* total number of ticks */ return(timer.total); /* return root counter value */ } /* Get current hsync counter value, start root counter 0 */ void StartTimer2(void) { HSyncStart2 = GetRCnt(1); /* get rc1's current value */ ResetRCnt(0); /* reset rc0 to count from zero */ StartRCnt(0); } /* Return number of clock ticks since StartTimer2 was called, the time passed in hsyncs and the percentage of frame time used are also stored in the timer2 structure */ int GetTimer2(void) { timer2.time = GetRCnt(0); /* get current value */ HSync2 = GetRCnt(1) - HSyncStart2; /* get difference */ if(HSync2 < 0) /* if less than zero, timer wrapped around */ HSync2 += CNTR_MAX; timer2.hsync = HSync2; timer2.percent = HSync2 * 100 / HSyncsPerFrame; /* timer wraps around every 30~31 hsyncs, calc total rc0 ticks */ HSync2 /= 31; timer2.total = timer2.time + (HSync2 << 16); /* total number of ticks */ return(timer2.total); }