最近一個項目中需要在VxWorks下使用一個高精度系統時鐘,要求精度為1ms,溢出時間大於5小時。VxWorks提供系統時鐘,該時鐘在作業系統啟動後開始計數,精度為1個tick,可以通過tickGet()擷取當前計數值。因為系統時鐘預設工作頻率為60Hz,則1個tick相當於16.7ms,不符號我們的精度要求。雖然可以通過sysClkRateSet(1000),把精度提高到1ms,但1kHz的系統時鐘中斷頻率會使得CPU的開銷大增。考慮到像nanoSleep()這樣的應用其計時精度可以達到納秒級,CPU中肯定有相應的ns級的時鐘提供。項目使用的硬體平台為PC104,處理器為300MHz X86相容CPU,在VxWorks函數手冊(vxworks_os_libraries_api_reference)中察看CPU相關的函數庫,果然在pentiumALib中找到pentiumTscGet32()、pentiumTscGet64()、pentiumTscReset() 這3個API可以對CPU中內建的TSC進行操作。TSC即Time Stamp Counter,為Pentium系列CPU提供的64位時戳計數器,該計數器在CPU上電或複位後每個指令周期計數一次,Intel保證TSC的溢出周期大於10年。像我們使用的300MHz的CPU,其TSC精度約為33ns,溢出周期約為19303年,這完全符合我們項目的要求。但令人faint的是,在downloadable project中包括了pentiumLib.h這個標頭檔後項目竟然不能編譯通過!無奈之下仔細察看手冊中對TSC相關函數的說明,手冊曰:這三個函數都是通過彙編實現的,要讀TSC寄存器只需使用RDTSC這條指令,它會將TSC的當前值低32位放入EAX寄存器,高32位放入EDX寄存器。那我豈不只要在我的應用程式中插入這麼一段彙編就可以了,關鍵是怎麼在VxWorks下使用C語言跟彙編混合編程呢?還好以前看過一點《Linux核心原始碼情景分析》,在上冊的第一章中就有關於GCC中C語言彙編混合編程的介紹,而VxWorks使用的編譯器正是GCC!那不妨就來試一試吧,於是有了下面的代碼:/**************************************************************************** getTsc - Get TSC count** 擷取TSC(時戳計數器)計數值,將計數器高位存入pHi,低位存入pLo** RETURNS: N/A*/void getTsc(unsigned int *pHi, unsigned int *pLo){ unsigned int hi, lo; __asm__ __volatile__( "rdtsc/n movl %%eax, %0/n movl %%edx, %1" :"=b"(lo),"=c"(hi) : :"memory" ); *pHi = hi; *pLo = lo;}/**************************************************************************** getTsc - Get the lower half of TSC count** 擷取TSC(時戳計數器)低32位計數值** RETURNS: TSC低32位計數值*/unsigned int getTsc32(void){ unsigned int tmp; __asm__ __volatile__( "rdtsc/n movl %%edx, %0" :"=c"(tmp) : :"memory" ); return tmp;}如果使用PowerPC平台,PowerPC提供的TB(Time Base)寄存器類似於Pentium的TSC,VxALib中提供vxTimeBaseSet() 和 vxTimeBaseGet()兩個函數來對TB寄存器進行讀寫操作。(感謝柏飛電子的FZZ提供PowrPC方面的支援人員!)