TSC backed timekeeping, 64-bit integer printing
[tpg/acess2.git] / Kernel / arch / x86 / time.c
1 /*
2  * Acess2 Kernel
3  * Timekeeping
4  * arch/x86/time.c
5  */
6 #include <acess.h>
7
8 // === MACROS ===
9 #define TIMER_QUANTUM   100
10 // 2^(15-rate), 15: 1HZ, 5: 1024Hz, 2: 8192Hz
11 // (Max: 15, Min: 2) - 15 = 1Hz, 13 = 4Hz, 12 = 8Hz, 11 = 16Hz 10 = 32Hz, 2 = 8192Hz
12 //#define TIMER_RATE    10      // 32 Hz
13 //#define TIMER_RATE    12      // 8 Hz
14 #define TIMER_RATE      14      // 2Hz
15 //#define TIMER_RATE    15      // 1HZ
16 #define TIMER_FREQ      (0x8000>>TIMER_RATE)    //Hz
17 #define MS_PER_TICK_WHOLE       (1000/(TIMER_FREQ))
18 #define MS_PER_TICK_FRACT       ((0x80000000*(1000%TIMER_FREQ))/TIMER_FREQ)
19
20 // === IMPORTS ===
21 extern volatile Sint64  giTimestamp;
22 extern volatile Uint64  giTicks;
23 extern volatile Uint64  giPartMiliseconds;
24 extern void     Timer_CallTimers(void);
25
26 // === GLOBALS ===
27 volatile Uint64 giTime_TSCAtLastTick = 0;
28 volatile Uint64 giTime_TSCPerTick = 0;
29
30 // === PROTOTYPES ===
31 Sint64  now(void);
32  int    Time_Setup(void);
33 void    Time_Interrupt(int);
34 Uint64  Time_ReadTSC(void);
35
36 // === CODE ===
37 /**
38  * \fn Sint64 now()
39  * \brief Return the current timestamp
40  */
41 Sint64 now(void)
42 {
43         Uint64  tsc = Time_ReadTSC();
44         tsc -= giTime_TSCAtLastTick;
45         tsc *= MS_PER_TICK_WHOLE;
46         if( giTime_TSCPerTick ) {
47                 tsc /= giTime_TSCPerTick;
48         }
49         else
50                 tsc = 0;
51         return giTimestamp + tsc;
52 }
53
54 /**
55  * \fn int Time_Setup(void)
56  * \brief Sets the system time from the Realtime-Clock
57  */
58 int Time_Setup(void)
59 {
60         Uint8   val;
61         
62         Log_Log("Timer", "RTC Timer firing at %iHz (%i divisor), %i.0x%08x",
63                 TIMER_FREQ, TIMER_RATE, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
64         
65         outb(0x70, inb(0x70)&0x7F);     // Disable NMIs
66         __asm__ __volatile__ ("cli");   // Disable normal interrupts
67         
68         // Set IRQ8 firing rate
69         outb(0x70, 0x0A);       // Set the index to register A
70         val = inb(0x71); // Get the current value of register A
71         outb(0x70, 0x0A); // Reset index to A
72         val &= 0xF0;
73         val |= TIMER_RATE;
74         outb(0x71, val);        // Update the timer rate
75                 
76         // Enable IRQ8
77         outb(0x70, 0x0B);       // Set the index to register B
78         val = inb(0x71);        // Read the current value of register B
79         outb(0x70, 0x0B);       // Set the index again (a read will reset the index to register D)
80         outb(0x71, val | 0x40); // Write the previous value or'd with 0x40. This turns on bit 6 of register D
81         
82         __asm__ __volatile__ ("sti");   // Re-enable normal interrupts
83         outb(0x70, inb(0x70)|0x80);     // Re-enable NMIs
84         
85         // Install IRQ Handler
86         IRQ_AddHandler(8, Time_Interrupt);
87         
88         // Make sure the RTC actually fires
89         outb(0x70, 0x0C); // Select register C
90         inb(0x71);      // Just throw away contents.
91         
92         return 0;
93 }
94
95 /**
96  * \brief Called on the timekeeping IRQ
97  * \param irq   IRQ number (unused)
98  */
99 void Time_Interrupt(int irq)
100 {
101         //Log("RTC Tick");
102         Uint64  curTSC = Time_ReadTSC();
103         
104         if( giTime_TSCAtLastTick )
105         {
106                 giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
107                 //Log("curTSC = %lli, giTime_TSCPerTick = %lli", curTSC, giTime_TSCPerTick);
108         }
109         giTime_TSCAtLastTick = curTSC;
110         
111         giTicks ++;
112         giTimestamp += MS_PER_TICK_WHOLE;
113         giPartMiliseconds += MS_PER_TICK_FRACT;
114         if(giPartMiliseconds > 0x80000000) {
115                 giTimestamp ++;
116                 giPartMiliseconds -= 0x80000000;
117         }
118         
119         Timer_CallTimers();
120
121         // Make sure the RTC Fires again
122         outb(0x70, 0x0C); // Select register C
123         inb(0x71);      // Just throw away contents.
124 }
125
126 #if 0
127 /**
128  * \fn void Time_TimerThread(void)
129  */
130 void Time_TimerThread(void)
131 {
132         Sint64  next;
133         Threads_SetName("TIMER");
134         
135         next = giTimestamp + TIMER_QUANTUM;
136         for(;;)
137         {
138                 while(giTimestamp < next)       Threads_Yield();
139                 next = giTimestamp + TIMER_QUANTUM;     
140                 Timer_CallTimers();
141         }
142 }
143 #endif
144
145 Uint64 Time_ReadTSC(void)
146 {
147         Uint32  a, d;
148         __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
149         return ((Uint64)d << 32) | a;
150 }

UCC git Repository :: git.ucc.asn.au