00001 #include "devices/timer.h"
00002
00003 #include <debug.h>
00004 #include <inttypes.h>
00005 #include <round.h>
00006 #include <stdio.h>
00007 #include "devices/pit.h"
00008 #include "threads/interrupt.h"
00009 #include "threads/synch.h"
00010 #include "threads/thread.h"
00011
00012
00013
00014 #if TIMER_FREQ < 19
00015 #error 8254 timer requires TIMER_FREQ >= 19
00016 #endif
00017 #if TIMER_FREQ > 1000
00018 #error TIMER_FREQ <= 1000 recommended
00019 #endif
00020
00021
00022 static int64_t ticks;
00023
00024
00025
00026 static unsigned loops_per_tick;
00027
00028 static intr_handler_func timer_interrupt;
00029 static bool too_many_loops (unsigned loops);
00030 static void busy_wait (int64_t loops);
00031 static void real_time_sleep (int64_t num, int32_t denom);
00032 static void real_time_delay (int64_t num, int32_t denom);
00033
00034
00035
00036 void
00037 timer_init (void)
00038 {
00039 pit_configure_channel (0, 2, TIMER_FREQ);
00040 intr_register_ext (0x20, timer_interrupt, "8254 Timer");
00041 }
00042
00043
00044 void
00045 timer_calibrate (void)
00046 {
00047 unsigned high_bit, test_bit;
00048
00049 ASSERT (intr_get_level () == INTR_ON);
00050 printf ("Calibrating timer... ");
00051
00052
00053
00054 loops_per_tick = 1u << 10;
00055 while (!too_many_loops (loops_per_tick << 1))
00056 {
00057 loops_per_tick <<= 1;
00058 ASSERT (loops_per_tick != 0);
00059 }
00060
00061
00062 high_bit = loops_per_tick;
00063 for (test_bit = high_bit >> 1; test_bit != high_bit >> 10; test_bit >>= 1)
00064 if (!too_many_loops (high_bit | test_bit))
00065 loops_per_tick |= test_bit;
00066
00067 printf ("%'"PRIu64" loops/s.\n", (uint64_t) loops_per_tick * TIMER_FREQ);
00068 }
00069
00070
00071 int64_t
00072 timer_ticks (void)
00073 {
00074 enum intr_level old_level = intr_disable ();
00075 int64_t t = ticks;
00076 intr_set_level (old_level);
00077 barrier ();
00078 return t;
00079 }
00080
00081
00082
00083 int64_t
00084 timer_elapsed (int64_t then)
00085 {
00086 return timer_ticks () - then;
00087 }
00088
00089
00090
00091 void
00092 timer_sleep (int64_t ticks)
00093 {
00094 int64_t start = timer_ticks ();
00095
00096 ASSERT (intr_get_level () == INTR_ON);
00097 while (timer_elapsed (start) < ticks)
00098 thread_yield ();
00099 }
00100
00101
00102
00103 void
00104 timer_msleep (int64_t ms)
00105 {
00106 real_time_sleep (ms, 1000);
00107 }
00108
00109
00110
00111 void
00112 timer_usleep (int64_t us)
00113 {
00114 real_time_sleep (us, 1000 * 1000);
00115 }
00116
00117
00118
00119 void
00120 timer_nsleep (int64_t ns)
00121 {
00122 real_time_sleep (ns, 1000 * 1000 * 1000);
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132 void
00133 timer_mdelay (int64_t ms)
00134 {
00135 real_time_delay (ms, 1000);
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145 void
00146 timer_udelay (int64_t us)
00147 {
00148 real_time_delay (us, 1000 * 1000);
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158 void
00159 timer_ndelay (int64_t ns)
00160 {
00161 real_time_delay (ns, 1000 * 1000 * 1000);
00162 }
00163
00164
00165 void
00166 timer_print_stats (void)
00167 {
00168 printf ("Timer: %"PRId64" ticks\n", timer_ticks ());
00169 }
00170
00171
00172 static void
00173 timer_interrupt (struct intr_frame *args UNUSED)
00174 {
00175 ticks++;
00176 thread_tick ();
00177 }
00178
00179
00180
00181 static bool
00182 too_many_loops (unsigned loops)
00183 {
00184
00185 int64_t start = ticks;
00186 while (ticks == start)
00187 barrier ();
00188
00189
00190 start = ticks;
00191 busy_wait (loops);
00192
00193
00194 barrier ();
00195 return start != ticks;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205 static void NO_INLINE
00206 busy_wait (int64_t loops)
00207 {
00208 while (loops-- > 0)
00209 barrier ();
00210 }
00211
00212
00213 static void
00214 real_time_sleep (int64_t num, int32_t denom)
00215 {
00216
00217
00218
00219
00220
00221
00222 int64_t ticks = num * TIMER_FREQ / denom;
00223
00224 ASSERT (intr_get_level () == INTR_ON);
00225 if (ticks > 0)
00226 {
00227
00228
00229
00230 timer_sleep (ticks);
00231 }
00232 else
00233 {
00234
00235
00236 real_time_delay (num, denom);
00237 }
00238 }
00239
00240
00241 static void
00242 real_time_delay (int64_t num, int32_t denom)
00243 {
00244
00245
00246 ASSERT (denom % 1000 == 0);
00247 busy_wait (loops_per_tick * num / 1000 * TIMER_FREQ / (denom / 1000));
00248 }