Difference between revisions of "Hardware Timers"

From Vita Development Wiki
Jump to navigation Jump to search
(→‎Configuration register: Refactor into tables)
(Add timer frequency estimates based on testing, change timers description, change some names in the timer's struct)
Line 1: Line 1:
The PSVita system embeds 8 Word timers (<code>SceWT0</code> to <code>SceWT7</code>) and 6 Longrange timers (<code>SceLT0</code> to <code>SceLT5</code>). The timers are counters incremented every ?microsecond?, can generate an interrupt when a certain value is reached or simply increase forever.
+
The PSVita system embeds 8 Word timers (<code>SceWT0</code> to <code>SceWT7</code>) and 6 Longrange timers (<code>SceLT0</code> to <code>SceLT5</code>). The timers consist of a counter that gets incremented at a fixed time interval, and can generate an interrupt when a certain value is reached.
  
 
Most timers are managed by [[SceSystimer]].
 
Most timers are managed by [[SceSystimer]].
Line 45: Line 45:
 
== Word Timers ==
 
== Word Timers ==
  
Timers with 32-bit counters.
+
Timers with 32-bit counters, incremented at an unknown frequency (seems to be in the order of ns).
 
<source lang="C">
 
<source lang="C">
 
typedef volatile _SceWordTimer {
 
typedef volatile _SceWordTimer {
 
     SceUInt32 unk0; // Value at which an interrupt is triggered?
 
     SceUInt32 unk0; // Value at which an interrupt is triggered?
     SceUInt32 unk4; // Current value of the timer counter?
+
     SceUInt32 current; // Current value of the timer's counter
     SceUInt32 unk8; // Configuration register?
+
     SceUInt32 cfg; // Configuration register
 
     SceUInt32 unkC; // Another counter?
 
     SceUInt32 unkC; // Another counter?
 
     SceUInt32 unk10; // Unused?
 
     SceUInt32 unk10; // Unused?
     SceUInt32 unk14; // Write 0x3 to clear interrupt?
+
     SceUInt32 unk14; // Interrupt status? Write 0x3 to clear pending IRQ?
   
 
    // Unused?
 
    SceUInt32 unk18;
 
    SceUInt32 unk1C;
 
    SceUInt32 unk20;
 
 
} SceWordTimer;
 
} SceWordTimer;
 
</source>
 
</source>
Line 64: Line 59:
 
== Long Timers ==
 
== Long Timers ==
  
Timers with 64-bit counters.
+
Timers with 64-bit counters. SceLT5 timer is incremented every microsecond (1MHz frequency).
 
<source lang="C">
 
<source lang="C">
 
typedef volatile _SceLongTimer {
 
typedef volatile _SceLongTimer {
     SceKernelSysClock unk0;  // Current value of the timer counter?
+
     SceKernelSysClock current;  // Current value of the timer counter
 
     SceKernelSysClock unk8;  // Value at which an interrupt is triggered?
 
     SceKernelSysClock unk8;  // Value at which an interrupt is triggered?
 
     SceKernelSysClock unk10; // Another counter?
 
     SceKernelSysClock unk10; // Another counter?
     SceUInt32 unk18; // Write 0x3 to clear interrupts?
+
     SceUInt32 unk18; // Interrupt status? Write 0x3 to clear pending IRQ?
     SceUInt32 unk1C; // Configuration register?
+
     SceUInt32 cfg; // Configuration register
    SceUInt32 unk20; // Unused
 
 
} SceLongTimer;
 
} SceLongTimer;
 
</source>
 
</source>

Revision as of 14:45, 13 July 2022

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 fixed time interval, 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.

List of timers
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 - ?may be accessible in Secure state only?

Word Timers

Timers with 32-bit counters, incremented at an unknown frequency (seems to be in the order of ns).

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 incremented 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 the PSVita 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* pTimerCounter) {
   SceKernelSysClock ctr;
   SceUInt32 ctrHi;
   do {
       ctr.hi = pTimeCounter->hi; //Read high word first
       ctr.lo = pTimeCounter->lo; //Read low word next
       ctrHi = pTimeCounter->hi;  //Read high word again to make sure no overflow happened
    } while (timerVal.hi != timerValHi); //Try again if high word changed while reading low word

    return ctr;
}

Configuration register

The configuration register bit mappings seems to be identical for Word and Long timers.

Known values
Timer Value Behaviour/notes
SceLT5 0x2F34500D Interrupt fired when counter reaches threshold
Configuration register bit mappings
Mask Effect Notes
0x00000001 Counting enable 0x0 = timer stopped, 0x1 = timer counting
0x0000000E ?
0x00000070 ? ?Mode select?
0x00000080 ?
0x00000700 ?
0x00000800 ? Unused?
0x0000F000 ?
0x000F0000 ?
0x00F00000 ?
0xFF000000 ?