Difference between revisions of "Hardware Timers"
Line 63: | Line 63: | ||
| 0xC | | 0xC | ||
| Secure Bus Error Attributes | | Secure Bus Error Attributes | ||
+ | |} | ||
+ | |||
+ | == Configuration register == | ||
+ | |||
+ | SysTimer Tick can be obtained by the following formula. | ||
+ | |||
+ | <code>1000000000 / (src_clk / (freqDiv + 1))</code> ns. | ||
+ | |||
+ | src_clk is from SysTimer 48Mhz or ScePower [[ScePower#scePowerSetSysClockFrequencyForDriver|SysClock]]. | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |+ tick example | ||
+ | |- | ||
+ | ! freq !! freqDiv !! Tick | ||
+ | |- | ||
+ | | 48Mhz || 0 || 20.833ns | ||
+ | |- | ||
+ | | 48Mhz || 47 || 1µs | ||
+ | |- | ||
+ | | 48Mhz || 0xFF || 5.333µs | ||
+ | |- | ||
+ | | 190Mhz || 0 || 5.263ns | ||
+ | |- | ||
+ | | 190Mhz || 0xFF || 1.347µs | ||
+ | |- | ||
+ | | 222Mhz || 0 || 4.5ns | ||
+ | |- | ||
+ | | 222Mhz || 0xFF || 1.152µs | ||
+ | |- | ||
+ | |} | ||
+ | |||
+ | The configuration register bit mappings seems to be identical for Word and Long timers. | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |+ Known values | ||
+ | |- | ||
+ | ! Timer !! Value !! Behaviour/notes | ||
+ | |- | ||
+ | | SceWT7 (SceTimerForUsleep) || 0xDD00000D || ~1MHz frequency, interrupt fired when counter reached threshold | ||
+ | |- | ||
+ | | SceLT5 || 0x2F34500D || 1MHz frequency, interrupt fired when counter reaches threshold | ||
+ | |- | ||
+ | |} | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |+ Configuration register bit mappings | ||
+ | |- | ||
+ | ! Mask !! Effect !! Notes | ||
+ | |- | ||
+ | | 0x00000001 || Counting enable || 0x0 = timer stopped, 0x1 = timer counting | ||
+ | |- | ||
+ | | 0x0000000E || ? || | ||
+ | |- | ||
+ | | 0x00000070</code> || ? || ?Mode select? | ||
+ | |- | ||
+ | | 0x00000080 || ? || | ||
+ | |- | ||
+ | | 0x00000700 || ? || | ||
+ | |- | ||
+ | | 0x00000800 || ? || Unused? | ||
+ | |- | ||
+ | | 0x0000F000 || ? || | ||
+ | |- | ||
+ | | 0x000F0000 || ? || | ||
+ | |- | ||
+ | | 0x00F00000 || ? || Related to frequency scaling | ||
+ | |- | ||
+ | | 0xFF000000 || freqDiv || Timer frequency is divided by this+1 (the higher the value to makes timer tick slower) | ||
|} | |} | ||
== Word Timers == | == Word Timers == | ||
− | Timers with 32-bit counters | + | Timers with 32-bit counters. |
<source lang="C"> | <source lang="C"> | ||
typedef volatile _SceWordTimer { | typedef volatile _SceWordTimer { | ||
Line 81: | Line 149: | ||
== Long Timers == | == Long Timers == | ||
− | Timers with 64-bit counters | + | Timers with 64-bit counters. |
SceLT5 timer is configured to increment every microsecond (1MHz frequency). | SceLT5 timer is configured to increment every microsecond (1MHz frequency). | ||
Line 113: | Line 181: | ||
} | } | ||
</source> | </source> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |
Revision as of 18:03, 11 August 2023
The PSVita system embeds 8 Word timers (SceWT0
to SceWT7
) and 6 Longrange timers (SceLT0
to SceLT5
). The timers consist of a counter that gets incremented at a configurable time interval (multiple of a base frequency?), and can generate an interrupt when a certain value is reached.
Most timers are managed by SceSystimer.
Available timers
The Address
column indicates the physical address at which the interface for a timer is located.
Each timer interface takes 0x1000 bytes.
Name | Address | Interrupt ID | Usage |
---|---|---|---|
SceLT0 / SceSystimerLongrangeTimer0 | 0xE20B1000 | 0x88 | Available for SceSystimer |
SceLT1 / SceSystimerLongrangeTimer1 | 0xE20B2000 | 0x89 | Available for SceSystimer |
SceLT2 / SceSystimerLongrangeTimer2 | 0xE20B3000 | 0x8A | Available for SceSystimer |
SceLT3 / SceSystimerLongrangeTimer3 | 0xE20B4000 | 0x8B | Available for SceSystimer |
SceLT4 / SceSystimerLongrangeTimer4 | 0xE20B5000 | 0x8C | Available for SceSystimer |
SceLT5 | 0xE20B6000 | 0x8D | Used by SceKernelThreadMgr as CPU timer |
SceWT0 / SceSystimerWordTimer0 | 0xE20B7000 | 0x80 | Available for SceSystimer |
SceWT1 / SceSystimerWordTimer1 | 0xE20B8000 | 0x81 | Available for SceSystimer |
SceWT2 / SceSystimerWordTimer2 | 0xE20B9000 | 0x82 | Available for SceSystimer |
SceWT3 / SceSystimerWordTimer3 | 0xE20BA000 | 0x83 | Available for SceSystimer |
SceWT4 / SceSystimerWordTimer4 | 0xE20BB000 | 0x84 | Available for SceSystimer |
SceWT5 / SceSystimerWordTimer5 | 0xE20BC000 | 0x85 | Available for SceSystimer |
SceWT6 / SceSystimerWordTimer6 | 0xE20BD000 | 0x86 | Available for SceSystimer |
SceWT7 / SceTimerForUsleep | 0xE20BE000 | 0x87 | Used by Tzs SceKernelIntrMgr for usleep |
Misc Reg
Miscellaneous features related to all timers can be accessed from an interface at physical address 0xE20BF000
.
Offset | Usage |
---|---|
0x0 | Bus Error Address |
0x4 | Bus Error Attributes |
0x8 | Secure Bus Error Address |
0xC | Secure Bus Error Attributes |
Configuration register
SysTimer Tick can be obtained by the following formula.
1000000000 / (src_clk / (freqDiv + 1))
ns.
src_clk is from SysTimer 48Mhz or ScePower SysClock.
freq | freqDiv | Tick |
---|---|---|
48Mhz | 0 | 20.833ns |
48Mhz | 47 | 1µs |
48Mhz | 0xFF | 5.333µs |
190Mhz | 0 | 5.263ns |
190Mhz | 0xFF | 1.347µs |
222Mhz | 0 | 4.5ns |
222Mhz | 0xFF | 1.152µs |
The configuration register bit mappings seems to be identical for Word and Long timers.
Timer | Value | Behaviour/notes |
---|---|---|
SceWT7 (SceTimerForUsleep) | 0xDD00000D | ~1MHz frequency, interrupt fired when counter reached threshold |
SceLT5 | 0x2F34500D | 1MHz frequency, interrupt fired when counter reaches threshold |
Mask | Effect | Notes |
---|---|---|
0x00000001 | Counting enable | 0x0 = timer stopped, 0x1 = timer counting |
0x0000000E | ? | |
0x00000070 | ? | ?Mode select? |
0x00000080 | ? | |
0x00000700 | ? | |
0x00000800 | ? | Unused? |
0x0000F000 | ? | |
0x000F0000 | ? | |
0x00F00000 | ? | Related to frequency scaling |
0xFF000000 | freqDiv | Timer frequency is divided by this+1 (the higher the value to makes timer tick slower) |
Word Timers
Timers with 32-bit counters.
typedef volatile _SceWordTimer {
SceUInt32 unk0; // Value at which an interrupt is triggered?
SceUInt32 current; // Current value of the timer's counter
SceUInt32 cfg; // Configuration register
SceUInt32 unkC; // Another counter?
SceUInt32 unk10; // Unused?
SceUInt32 unk14; // Interrupt status? Write 0x3 to clear pending IRQ?
} SceWordTimer;
Long Timers
Timers with 64-bit counters.
SceLT5 timer is configured to increment every microsecond (1MHz frequency).
typedef volatile _SceLongTimer {
SceKernelSysClock current; // Current value of the timer counter
SceKernelSysClock unk8; // Value at which an interrupt is triggered?
SceKernelSysClock unk10; // Another counter?
SceUInt32 unk18; // Interrupt status? Write 0x3 to clear pending IRQ?
SceUInt32 cfg; // Configuration register
} SceLongTimer;
NOTE: On ARMv7 processors that do not support the Large Physical Address Extension, such as the PS Vita's CPU, 64-bit accesses are not guaranteed to be atomic.
This can lead to issues when reading the timer if the low word of a counter is about to overflow.
To ensure the readings from a timer are accurate, use code similar to the following code:
//Return value should hopefully be optimized into registers
SceKernelSysClock readCounter(volatile SceKernelSysClock* pTimer) {
SceKernelSysClock ctr;
SceUInt32 ctrHi;
do {
ctr.u.hi = pTimer->u.hi; //Read high word first
ctr.u.lo = pTimer->u.lo; //Read low word next
ctrHi = pTimer->u.hi; //Read high word again to make sure no overflow happened
} while (ctr.hi != ctrHi); //Try again if high word changed while reading low word
return ctr;
}