see also HighFrequencyCounterInC
This is a quickie program I needed to detect a system's CPU speed from a DOS prompt. This code listing is ugly and needs a cleanup but wanted to preserve it before I lost it.

I used the djgpp compiler (from http://www.delorie.com/djgpp). Along the way I learned a lot more about assembler, AT&T assembler differences and the 8245.

#include <stdio.h>

int warmup ()
{
   int subtime;
        
   __asm__(
        "cpuid\n"
        "rdtsc\n"
        "movl %%eax, %0\n"
        "cpuid\n"
        "rdtsc\n"
        "subl %0, %%eax\n"
        "movl %%eax, %0\n"
        :
        : "g" (subtime)
        );

           __asm__(
        "cpuid\n"
        "rdtsc\n"
        "movl %%eax, %0\n"
        "cpuid\n"
        "rdtsc\n"
        "subl %0, %%eax\n"
        "movl %%eax, %0\n"
        :
        : "g" (subtime)
        );

           __asm__(
        "cpuid\n"
        "rdtsc\n"
        "movl %%eax, %0\n"
        "cpuid\n"
        "rdtsc\n"
        "subl %0, %%eax\n"
        "movl %%eax, %0\n"
        :
        : "g" (subtime)
        );

        return subtime;
}

void start_timer()
{
 __asm__ __volatile__(
 "mov $0x34, %al\n"
 "out %al, $0x43\n"
 "sub %al, %al\n"
 "out %al, $0x40\n"
 "out %al, $0x40\n"
 );

}

unsigned int read_8254()
{
 unsigned int clock = 0;
 unsigned int high = 0;
 unsigned int low = 0;
 
 __asm__ __volatile__(
 "pushf\n"
 "cli\n"
 "movb $0, %%al\n"
 "out %%al, $0x43\n"
 "in $0x40, %%al\n"
 "movb %%al, %1\n"
 "in $0x40, %%al\n"
 "movb %%al, %0\n"
 "sti\n"
 "popf\n"
 : "=g" (high), "=g" (low)
 );

// printf("%02x - %02x :: ", high, low);

// outb(0x00, 0x43);
// low = inb(0x40);
// high = inb(0x40);

// clock = low;
 clock = (high << 8) | low;
// printf("%x\n", clock);

 return clock;
 
}

long long get_rdtsc(void)
{
 unsigned int lower_word = 0;
 unsigned int upper_word = 0;
 unsigned long long total_word = 0;

 __asm__ __volatile__(
 "cpuid\n"
 "rdtsc\n"
 : "=a" (lower_word), "=d" (upper_word));

// printf("ticks now = %010x %010x\n", upper_word, lower_word);
 total_word = ( (unsigned long long) upper_word)  | lower_word;
// printf("ticks now = %010lx\n", total_word);
 return lower_word;

}

int get_cpu_speed(void)
{
 int warmup_time;
 long t1, t2;
 unsigned int clock1 = 0;
 unsigned int clock2 = 0;
 unsigned int cpu_speed;
 int done = 0;

 warmup_time = warmup();

// while ((inb(0x61) & 0x20) == 0);
 
// printf("warmup = %d\n", warmup_time);

 start_timer();
 do
 {
  t1 = get_rdtsc();
  clock1 = read_8254();
 } while (clock1 < 0xFE00);

 do
 {
  t2 = get_rdtsc();
  clock2 = read_8254();
 } while (clock2 > 0x0E00);


 t2 = get_rdtsc() - t1 - 2*warmup_time;

 clock2 = clock1 - clock2;
 
// printf("RDTSC ticks == %lu -- ", t2);
// printf(" clock diff  == %lu -- ", clock2);

 cpu_speed = ( t2 * 1.193180) / clock2;
 return cpu_speed;
}

int main(void)
{
 unsigned int freq;
 int done = 0;
 int i, j;

 printf("DOS CPU Frequency Detector\n");
// while(!done)
// {
// freq = get_cpu_speed();
 printf("CPU speed == %u\n", freq);
// if (freq > 370 || freq < 358)
// {
//  done = 1;
// }
 
 }
 /* Test routine - should spit out a . once a second
 */
 /*
 for (j = 0; j < 10; j++)
 {
 for (i = 0; i < 18; i++)
 // wait for clock
 {
 while(read_8254() < 0xFe00);
 while(read_8254() > 0x0e00);
 }
 printf(".");
 }
 */
 return freq;
}

-- MattWalsh - 11 Aug 2003

Topic attachments
I Attachment Action Size Date Who Comment
Microsoft Executable fileexe dostimer.exe manage 79.4 K 12 Aug 2003 - 17:32 MattWalsh  
Topic revision: r2 - 12 Aug 2003 - MattWalsh
 
This site is powered by the TWiki collaboration platformCopyright © 2008-2012 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback