Add code for AmigaOne board
(preliminary merge to U-Boot, still WIP)
* Patch by Jon Diekema, 12 Nov 2002:
- Adding URL for IEEE OUI lookup
- Making the autoboot #defines dependent on CONFIG_AUTOBOOT_KEYED
being defined.
- In the CONFIG_EXTRA_ENV_SETTINGS #define, the root-on-initrd and
root-on-nfs macros are designed to switch how the default boot
method gets defined.
809 lines
25 KiB
C
809 lines
25 KiB
C
/****************************************************************************
|
|
*
|
|
* SciTech OS Portability Manager Library
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* The contents of this file are subject to the SciTech MGL Public
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.scitechsoft.com/mgl-license.txt
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
|
|
*
|
|
* The Initial Developer of the Original Code is SciTech Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Language: ANSI C
|
|
* Environment: Any
|
|
*
|
|
* Description: Main module to implement the Zen Timer support functions.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "ztimer.h"
|
|
#include "pmapi.h"
|
|
#include "oshdr.h"
|
|
#if !defined(__WIN32_VXD__) && !defined(__OS2_VDD__) && !defined(__NT_DRIVER__)
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#endif
|
|
|
|
/*----------------------------- Implementation ----------------------------*/
|
|
|
|
/* External Intel assembler functions */
|
|
#ifdef __INTEL__
|
|
/* {secret} */
|
|
ibool _ASMAPI _CPU_haveCPUID(void);
|
|
/* {secret} */
|
|
ibool _ASMAPI _CPU_check80386(void);
|
|
/* {secret} */
|
|
ibool _ASMAPI _CPU_check80486(void);
|
|
/* {secret} */
|
|
uint _ASMAPI _CPU_checkCPUID(void);
|
|
/* {secret} */
|
|
uint _ASMAPI _CPU_getCPUIDModel(void);
|
|
/* {secret} */
|
|
uint _ASMAPI _CPU_getCPUIDStepping(void);
|
|
/* {secret} */
|
|
uint _ASMAPI _CPU_getCPUIDFeatures(void);
|
|
/* {secret} */
|
|
uint _ASMAPI _CPU_getCacheSize(void);
|
|
/* {secret} */
|
|
uint _ASMAPI _CPU_have3DNow(void);
|
|
/* {secret} */
|
|
ibool _ASMAPI _CPU_checkClone(void);
|
|
/* {secret} */
|
|
void _ASMAPI _CPU_readTimeStamp(CPU_largeInteger *time);
|
|
/* {secret} */
|
|
void _ASMAPI _CPU_runBSFLoop(ulong iterations);
|
|
/* {secret} */
|
|
ulong _ASMAPI _CPU_mulDiv(ulong a,ulong b,ulong c);
|
|
/* {secret} */
|
|
void ZTimerQuickInit(void);
|
|
#define CPU_HaveMMX 0x00800000
|
|
#define CPU_HaveRDTSC 0x00000010
|
|
#define CPU_HaveSSE 0x02000000
|
|
#endif
|
|
|
|
#if defined(__SMX32__)
|
|
#include "smx/cpuinfo.c"
|
|
#elif defined(__RTTARGET__)
|
|
#include "rttarget/cpuinfo.c"
|
|
#elif defined(__REALDOS__)
|
|
#include "dos/cpuinfo.c"
|
|
#elif defined(__NT_DRIVER__)
|
|
#include "ntdrv/cpuinfo.c"
|
|
#elif defined(__WIN32_VXD__)
|
|
#include "vxd/cpuinfo.c"
|
|
#elif defined(__WINDOWS32__)
|
|
#include "win32/cpuinfo.c"
|
|
#elif defined(__OS2_VDD__)
|
|
#include "vdd/cpuinfo.c"
|
|
#elif defined(__OS2__)
|
|
#include "os2/cpuinfo.c"
|
|
#elif defined(__LINUX__)
|
|
#include "linux/cpuinfo.c"
|
|
#elif defined(__QNX__)
|
|
#include "qnx/cpuinfo.c"
|
|
#elif defined(__BEOS__)
|
|
#include "beos/cpuinfo.c"
|
|
#else
|
|
#error CPU library not ported to this platform yet!
|
|
#endif
|
|
|
|
/*------------------------ Public interface routines ----------------------*/
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Read an I/O port location.
|
|
****************************************************************************/
|
|
static uchar rdinx(
|
|
int port,
|
|
int index)
|
|
{
|
|
PM_outpb(port,(uchar)index);
|
|
return PM_inpb(port+1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Write an I/O port location.
|
|
****************************************************************************/
|
|
static void wrinx(
|
|
ushort port,
|
|
ushort index,
|
|
ushort value)
|
|
{
|
|
PM_outpb(port,(uchar)index);
|
|
PM_outpb(port+1,(uchar)value);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Enables the Cyrix CPUID instruction to properly detect MediaGX and 6x86
|
|
processors.
|
|
****************************************************************************/
|
|
static void _CPU_enableCyrixCPUID(void)
|
|
{
|
|
uchar ccr3;
|
|
|
|
PM_init();
|
|
ccr3 = rdinx(0x22,0xC3);
|
|
wrinx(0x22,0xC3,(uchar)(ccr3 | 0x10));
|
|
wrinx(0x22,0xE8,(uchar)(rdinx(0x22,0xE8) | 0x80));
|
|
wrinx(0x22,0xC3,ccr3);
|
|
}
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Returns the type of processor in the system.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
RETURNS:
|
|
Numerical identifier for the installed processor
|
|
|
|
REMARKS:
|
|
Returns the type of processor in the system. Note that if the CPU is an
|
|
unknown Pentium family processor that we don't have an enumeration for,
|
|
the return value will be greater than or equal to the value of CPU_UnkPentium
|
|
(depending on the value returned by the CPUID instruction).
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorSpeed, CPU_haveMMX, CPU_getProcessorName
|
|
****************************************************************************/
|
|
uint ZAPI CPU_getProcessorType(void)
|
|
{
|
|
#if defined(__INTEL__)
|
|
uint cpu,vendor,model,cacheSize;
|
|
static ibool firstTime = true;
|
|
|
|
if (_CPU_haveCPUID()) {
|
|
cpu = _CPU_checkCPUID();
|
|
vendor = cpu & ~CPU_mask;
|
|
if (vendor == CPU_Intel) {
|
|
/* Check for Intel processors */
|
|
switch (cpu & CPU_mask) {
|
|
case 4: cpu = CPU_i486; break;
|
|
case 5: cpu = CPU_Pentium; break;
|
|
case 6:
|
|
if ((model = _CPU_getCPUIDModel()) == 1)
|
|
cpu = CPU_PentiumPro;
|
|
else if (model <= 6) {
|
|
cacheSize = _CPU_getCacheSize();
|
|
if ((model == 5 && cacheSize == 0) ||
|
|
(model == 5 && cacheSize == 256) ||
|
|
(model == 6 && cacheSize == 128))
|
|
cpu = CPU_Celeron;
|
|
else
|
|
cpu = CPU_PentiumII;
|
|
}
|
|
else if (model >= 7) {
|
|
/* Model 7 == Pentium III */
|
|
/* Model 8 == Celeron/Pentium III Coppermine */
|
|
cacheSize = _CPU_getCacheSize();
|
|
if ((model == 8 && cacheSize == 128))
|
|
cpu = CPU_Celeron;
|
|
else
|
|
cpu = CPU_PentiumIII;
|
|
}
|
|
break;
|
|
default:
|
|
cpu = CPU_UnkIntel;
|
|
}
|
|
}
|
|
else if (vendor == CPU_Cyrix) {
|
|
/* Check for Cyrix processors */
|
|
switch (cpu & CPU_mask) {
|
|
case 4:
|
|
if ((model = _CPU_getCPUIDModel()) == 4)
|
|
cpu = CPU_CyrixMediaGX;
|
|
else
|
|
cpu = CPU_UnkCyrix;
|
|
break;
|
|
case 5:
|
|
if ((model = _CPU_getCPUIDModel()) == 2)
|
|
cpu = CPU_Cyrix6x86;
|
|
else if (model == 4)
|
|
cpu = CPU_CyrixMediaGXm;
|
|
else
|
|
cpu = CPU_UnkCyrix;
|
|
break;
|
|
case 6:
|
|
if ((model = _CPU_getCPUIDModel()) <= 1)
|
|
cpu = CPU_Cyrix6x86MX;
|
|
else
|
|
cpu = CPU_UnkCyrix;
|
|
break;
|
|
default:
|
|
cpu = CPU_UnkCyrix;
|
|
}
|
|
}
|
|
else if (vendor == CPU_AMD) {
|
|
/* Check for AMD processors */
|
|
switch (cpu & CPU_mask) {
|
|
case 4:
|
|
if ((model = _CPU_getCPUIDModel()) == 0)
|
|
cpu = CPU_AMDAm5x86;
|
|
else
|
|
cpu = CPU_AMDAm486;
|
|
break;
|
|
case 5:
|
|
if ((model = _CPU_getCPUIDModel()) <= 3)
|
|
cpu = CPU_AMDK5;
|
|
else if (model <= 7)
|
|
cpu = CPU_AMDK6;
|
|
else if (model == 8)
|
|
cpu = CPU_AMDK6_2;
|
|
else if (model == 9)
|
|
cpu = CPU_AMDK6_III;
|
|
else if (model == 13) {
|
|
if (_CPU_getCPUIDStepping() <= 3)
|
|
cpu = CPU_AMDK6_IIIplus;
|
|
else
|
|
cpu = CPU_AMDK6_2plus;
|
|
}
|
|
else
|
|
cpu = CPU_UnkAMD;
|
|
break;
|
|
case 6:
|
|
if ((model = _CPU_getCPUIDModel()) == 3)
|
|
cpu = CPU_AMDDuron;
|
|
else
|
|
cpu = CPU_AMDAthlon;
|
|
break;
|
|
default:
|
|
cpu = CPU_UnkAMD;
|
|
}
|
|
}
|
|
else if (vendor == CPU_IDT) {
|
|
/* Check for IDT WinChip processors */
|
|
switch (cpu & CPU_mask) {
|
|
case 5:
|
|
if ((model = _CPU_getCPUIDModel()) <= 4)
|
|
cpu = CPU_WinChipC6;
|
|
else if (model == 8)
|
|
cpu = CPU_WinChip2;
|
|
else
|
|
cpu = CPU_UnkIDT;
|
|
break;
|
|
default:
|
|
cpu = CPU_UnkIDT;
|
|
}
|
|
}
|
|
else {
|
|
/* Assume a Pentium compatible Intel clone */
|
|
cpu = CPU_Pentium;
|
|
}
|
|
return cpu | vendor | (_CPU_getCPUIDStepping() << CPU_steppingShift);
|
|
}
|
|
else {
|
|
if (_CPU_check80386())
|
|
cpu = CPU_i386;
|
|
else if (_CPU_check80486()) {
|
|
/* If we get here we may have a Cyrix processor so we can try
|
|
* enabling the CPUID instruction and trying again.
|
|
*/
|
|
if (firstTime) {
|
|
firstTime = false;
|
|
_CPU_enableCyrixCPUID();
|
|
return CPU_getProcessorType();
|
|
}
|
|
cpu = CPU_i486;
|
|
}
|
|
else
|
|
cpu = CPU_Pentium;
|
|
if (!_CPU_checkClone())
|
|
return cpu | CPU_Intel;
|
|
return cpu;
|
|
}
|
|
#elif defined(__ALPHA__)
|
|
return CPU_Alpha;
|
|
#elif defined(__MIPS__)
|
|
return CPU_Mips;
|
|
#elif defined(__PPC__)
|
|
return CPU_PowerPC;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Returns true if the processor supports Intel MMX extensions.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
RETURNS:
|
|
True if MMX is available, false if not.
|
|
|
|
REMARKS:
|
|
This function determines if the processor supports the Intel MMX extended
|
|
instruction set.
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorType, CPU_getProcessorSpeed, CPU_have3DNow, CPU_haveSSE,
|
|
CPU_getProcessorName
|
|
****************************************************************************/
|
|
ibool ZAPI CPU_haveMMX(void)
|
|
{
|
|
#ifdef __INTEL__
|
|
if (_CPU_haveCPUID())
|
|
return (_CPU_getCPUIDFeatures() & CPU_HaveMMX) != 0;
|
|
return false;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Returns true if the processor supports AMD 3DNow! extensions.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
RETURNS:
|
|
True if 3DNow! is available, false if not.
|
|
|
|
REMARKS:
|
|
This function determines if the processor supports the AMD 3DNow! extended
|
|
instruction set.
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_haveSSE,
|
|
CPU_getProcessorName
|
|
****************************************************************************/
|
|
ibool ZAPI CPU_have3DNow(void)
|
|
{
|
|
#ifdef __INTEL__
|
|
if (_CPU_haveCPUID())
|
|
return _CPU_have3DNow();
|
|
return false;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Returns true if the processor supports Intel KNI extensions.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
RETURNS:
|
|
True if Intel KNI is available, false if not.
|
|
|
|
REMARKS:
|
|
This function determines if the processor supports the Intel KNI extended
|
|
instruction set.
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow,
|
|
CPU_getProcessorName
|
|
****************************************************************************/
|
|
ibool ZAPI CPU_haveSSE(void)
|
|
{
|
|
#ifdef __INTEL__
|
|
if (_CPU_haveCPUID())
|
|
return (_CPU_getCPUIDFeatures() & CPU_HaveSSE) != 0;
|
|
return false;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
RETURNS:
|
|
True if the RTSC instruction is available, false if not.
|
|
|
|
REMARKS:
|
|
This function determines if the processor supports the Intel RDTSC
|
|
instruction, for high precision timing. If the processor is not an Intel or
|
|
Intel clone CPU, this function will always return false.
|
|
|
|
DESCRIPTION:
|
|
Returns true if the processor supports RDTSC extensions.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
RETURNS:
|
|
True if RTSC is available, false if not.
|
|
|
|
REMARKS:
|
|
This function determines if the processor supports the RDTSC instruction
|
|
for reading the processor time stamp counter.
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow,
|
|
CPU_getProcessorName
|
|
****************************************************************************/
|
|
ibool ZAPI CPU_haveRDTSC(void)
|
|
{
|
|
#ifdef __INTEL__
|
|
if (_CPU_haveCPUID())
|
|
return (_CPU_getCPUIDFeatures() & CPU_HaveRDTSC) != 0;
|
|
return false;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
#ifdef __INTEL__
|
|
|
|
#define ITERATIONS 16000
|
|
#define SAMPLINGS 2
|
|
#define INNER_LOOPS 400
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
If processor does not support time stamp reading, but is at least a 386 or
|
|
above, utilize method of timing a loop of BSF instructions which take a
|
|
known number of cycles to run on i386(tm), i486(tm), and Pentium(R)
|
|
processors.
|
|
****************************************************************************/
|
|
static ulong GetBSFCpuSpeed(
|
|
ulong cycles)
|
|
{
|
|
CPU_largeInteger t0,t1,count_freq;
|
|
ulong ticks; /* Microseconds elapsed during test */
|
|
ulong current; /* Variable to store time elapsed */
|
|
int i,j,iPriority;
|
|
ulong lowest = (ulong)-1;
|
|
|
|
iPriority = SetMaxThreadPriority();
|
|
GetCounterFrequency(&count_freq);
|
|
for (i = 0; i < SAMPLINGS; i++) {
|
|
GetCounter(&t0);
|
|
for (j = 0; j < INNER_LOOPS; j++)
|
|
_CPU_runBSFLoop(ITERATIONS);
|
|
GetCounter(&t1);
|
|
current = t1.low - t0.low;
|
|
if (current < lowest)
|
|
lowest = current;
|
|
}
|
|
RestoreThreadPriority(iPriority);
|
|
|
|
/* Compute frequency */
|
|
ticks = _CPU_mulDiv(lowest,1000000,count_freq.low);
|
|
if ((ticks % count_freq.low) > (count_freq.low/2))
|
|
ticks++; /* Round up if necessary */
|
|
if (ticks == 0)
|
|
return 0;
|
|
return ((cycles*INNER_LOOPS)/ticks);
|
|
}
|
|
|
|
#define TOLERANCE 1
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
On processors supporting the Read Time Stamp opcode, compare elapsed
|
|
time on the High-Resolution Counter with elapsed cycles on the Time
|
|
Stamp Register.
|
|
|
|
The inner loop runs up to 20 times oruntil the average of the previous
|
|
three calculated frequencies is within 1 MHz of each of the individual
|
|
calculated frequencies. This resampling increases the accuracy of the
|
|
results since outside factors could affect this calculation.
|
|
****************************************************************************/
|
|
static ulong GetRDTSCCpuSpeed(
|
|
ibool accurate)
|
|
{
|
|
CPU_largeInteger t0,t1,s0,s1,count_freq;
|
|
u64 stamp0, stamp1, ticks0, ticks1;
|
|
u64 total_cycles, cycles, hz, freq;
|
|
u64 total_ticks, ticks;
|
|
int tries,iPriority;
|
|
ulong maxCount;
|
|
|
|
PM_set64_32(total_cycles,0);
|
|
PM_set64_32(total_ticks,0);
|
|
maxCount = accurate ? 600000 : 30000;
|
|
iPriority = SetMaxThreadPriority();
|
|
GetCounterFrequency(&count_freq);
|
|
PM_set64(freq,count_freq.high,count_freq.low);
|
|
for (tries = 0; tries < 3; tries++) {
|
|
/* Loop until 100 ticks have passed since last read of hi-res
|
|
* counter. This accounts for overhead later.
|
|
*/
|
|
GetCounter(&t0);
|
|
t1.low = t0.low;
|
|
t1.high = t0.high;
|
|
while ((t1.low - t0.low) < 100) {
|
|
GetCounter(&t1);
|
|
_CPU_readTimeStamp(&s0);
|
|
}
|
|
|
|
/* Loop until 30000 ticks have passed since last read of hi-res counter.
|
|
* This allows for elapsed time for sampling. For a hi-res frequency
|
|
* of 1MHz, this is about 0.03 of a second. The frequency reported
|
|
* by the OS dependent code should be tuned to provide a good
|
|
* sample period depending on the accuracy of the OS timers (ie:
|
|
* if the accuracy is lower, lower the frequency to spend more time
|
|
* in the inner loop to get better accuracy).
|
|
*/
|
|
t0.low = t1.low;
|
|
t0.high = t1.high;
|
|
while ((t1.low - t0.low) < maxCount) {
|
|
GetCounter(&t1);
|
|
_CPU_readTimeStamp(&s1);
|
|
}
|
|
|
|
/* Find the difference during the timing loop */
|
|
PM_set64(stamp0,s0.high,s0.low);
|
|
PM_set64(stamp1,s1.high,s1.low);
|
|
PM_set64(ticks0,t0.high,t0.low);
|
|
PM_set64(ticks1,t1.high,t1.low);
|
|
PM_sub64(cycles,stamp1,stamp0);
|
|
PM_sub64(ticks,ticks1,ticks0);
|
|
|
|
/* Sum up the results */
|
|
PM_add64(total_ticks,total_ticks,ticks);
|
|
PM_add64(total_cycles,total_cycles,cycles);
|
|
}
|
|
RestoreThreadPriority(iPriority);
|
|
|
|
/* Compute frequency in Hz */
|
|
PM_mul64(hz,total_cycles,freq);
|
|
PM_div64(hz,hz,total_ticks);
|
|
return PM_64to32(hz);
|
|
}
|
|
|
|
#endif /* __INTEL__ */
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Returns the speed of the processor in MHz.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
PARAMETERS:
|
|
accurate - True of the speed should be measured accurately
|
|
|
|
RETURNS:
|
|
Processor speed in MHz.
|
|
|
|
REMARKS:
|
|
This function returns the speed of the CPU in MHz. Note that if the speed
|
|
cannot be determined, this function will return 0.
|
|
|
|
If the accurate parameter is set to true, this function will spend longer
|
|
profiling the speed of the CPU, and will not round the CPU speed that is
|
|
reported. This is important for highly accurate timing using the Pentium
|
|
RDTSC instruction, but it does take a lot longer for the profiling to
|
|
produce accurate results.
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorSpeedInHz, CPU_getProcessorType, CPU_haveMMX,
|
|
CPU_getProcessorName
|
|
****************************************************************************/
|
|
ulong ZAPI CPU_getProcessorSpeed(
|
|
ibool accurate)
|
|
{
|
|
#if defined(__INTEL__)
|
|
/* Number of cycles needed to execute a single BSF instruction on i386+
|
|
* processors.
|
|
*/
|
|
ulong cpuSpeed;
|
|
uint i;
|
|
static ulong intel_cycles[] = {
|
|
115,47,43,
|
|
};
|
|
static ulong cyrix_cycles[] = {
|
|
38,38,52,52,
|
|
};
|
|
static ulong amd_cycles[] = {
|
|
49,
|
|
};
|
|
static ulong known_speeds[] = {
|
|
1000,950,900,850,800,750,700,650,600,550,500,450,433,400,350,
|
|
333,300,266,233,200,166,150,133,120,100,90,75,66,60,50,33,20,0,
|
|
};
|
|
|
|
if (CPU_haveRDTSC()) {
|
|
cpuSpeed = (GetRDTSCCpuSpeed(accurate) + 500000) / 1000000;
|
|
}
|
|
else {
|
|
int type = CPU_getProcessorType();
|
|
int processor = type & CPU_mask;
|
|
int vendor = type & CPU_familyMask;
|
|
if (vendor == CPU_Intel)
|
|
cpuSpeed = GetBSFCpuSpeed(ITERATIONS * intel_cycles[processor - CPU_i386]);
|
|
else if (vendor == CPU_Cyrix)
|
|
cpuSpeed = GetBSFCpuSpeed(ITERATIONS * cyrix_cycles[processor - CPU_Cyrix6x86]);
|
|
else if (vendor == CPU_AMD)
|
|
cpuSpeed = GetBSFCpuSpeed(ITERATIONS * amd_cycles[0]);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* Now normalise the results given known processors speeds, if the
|
|
* speed we measure is within 2MHz of the expected values
|
|
*/
|
|
if (!accurate) {
|
|
for (i = 0; known_speeds[i] != 0; i++) {
|
|
if (cpuSpeed >= (known_speeds[i]-3) && cpuSpeed <= (known_speeds[i]+3)) {
|
|
return known_speeds[i];
|
|
}
|
|
}
|
|
}
|
|
return cpuSpeed;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Returns the speed of the processor in Hz.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
RETURNS:
|
|
Accurate processor speed in Hz.
|
|
|
|
REMARKS:
|
|
This function returns the accurate speed of the CPU in Hz. Note that if the
|
|
speed cannot be determined, this function will return 0.
|
|
|
|
This function is similar to the CPU_getProcessorSpeed function, except that
|
|
it attempts to accurately measure the CPU speed in Hz. This is used
|
|
internally in the Zen Timer libraries to provide accurate real world timing
|
|
information. This is important for highly accurate timing using the Pentium
|
|
RDTSC instruction, but it does take a lot longer for the profiling to
|
|
produce accurate results.
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorSpeed, CPU_getProcessorType, CPU_haveMMX,
|
|
CPU_getProcessorName
|
|
****************************************************************************/
|
|
ulong ZAPI CPU_getProcessorSpeedInHZ(
|
|
ibool accurate)
|
|
{
|
|
#if defined(__INTEL__)
|
|
if (CPU_haveRDTSC()) {
|
|
return GetRDTSCCpuSpeed(accurate);
|
|
}
|
|
return CPU_getProcessorSpeed(false) * 1000000;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Returns a string defining the speed and name of the processor.
|
|
|
|
HEADER:
|
|
ztimer.h
|
|
|
|
RETURNS:
|
|
Processor name string.
|
|
|
|
REMARKS:
|
|
This function returns an English string describing the speed and name of the
|
|
CPU.
|
|
|
|
SEE ALSO:
|
|
CPU_getProcessorType, CPU_haveMMX, CPU_getProcessorName
|
|
****************************************************************************/
|
|
char * ZAPI CPU_getProcessorName(void)
|
|
{
|
|
#if defined(__INTEL__)
|
|
static int cpu,speed = -1;
|
|
static char name[80];
|
|
|
|
if (speed == -1) {
|
|
cpu = CPU_getProcessorType();
|
|
speed = CPU_getProcessorSpeed(false);
|
|
}
|
|
sprintf(name,"%d MHz ", speed);
|
|
switch (cpu & CPU_mask) {
|
|
case CPU_i386:
|
|
strcat(name,"Intel i386 processor");
|
|
break;
|
|
case CPU_i486:
|
|
strcat(name,"Intel i486 processor");
|
|
break;
|
|
case CPU_Pentium:
|
|
strcat(name,"Intel Pentium processor");
|
|
break;
|
|
case CPU_PentiumPro:
|
|
strcat(name,"Intel Pentium Pro processor");
|
|
break;
|
|
case CPU_PentiumII:
|
|
strcat(name,"Intel Pentium II processor");
|
|
break;
|
|
case CPU_Celeron:
|
|
strcat(name,"Intel Celeron processor");
|
|
break;
|
|
case CPU_PentiumIII:
|
|
strcat(name,"Intel Pentium III processor");
|
|
break;
|
|
case CPU_UnkIntel:
|
|
strcat(name,"Unknown Intel processor");
|
|
break;
|
|
case CPU_Cyrix6x86:
|
|
strcat(name,"Cyrix 6x86 processor");
|
|
break;
|
|
case CPU_Cyrix6x86MX:
|
|
strcat(name,"Cyrix 6x86MX processor");
|
|
break;
|
|
case CPU_CyrixMediaGX:
|
|
strcat(name,"Cyrix MediaGX processor");
|
|
break;
|
|
case CPU_CyrixMediaGXm:
|
|
strcat(name,"Cyrix MediaGXm processor");
|
|
break;
|
|
case CPU_UnkCyrix:
|
|
strcat(name,"Unknown Cyrix processor");
|
|
break;
|
|
case CPU_AMDAm486:
|
|
strcat(name,"AMD Am486 processor");
|
|
break;
|
|
case CPU_AMDAm5x86:
|
|
strcat(name,"AMD Am5x86 processor");
|
|
break;
|
|
case CPU_AMDK5:
|
|
strcat(name,"AMD K5 processor");
|
|
break;
|
|
case CPU_AMDK6:
|
|
strcat(name,"AMD K6 processor");
|
|
break;
|
|
case CPU_AMDK6_2:
|
|
strcat(name,"AMD K6-2 processor");
|
|
break;
|
|
case CPU_AMDK6_III:
|
|
strcat(name,"AMD K6-III processor");
|
|
break;
|
|
case CPU_AMDK6_2plus:
|
|
strcat(name,"AMD K6-2+ processor");
|
|
break;
|
|
case CPU_AMDK6_IIIplus:
|
|
strcat(name,"AMD K6-III+ processor");
|
|
break;
|
|
case CPU_UnkAMD:
|
|
strcat(name,"Unknown AMD processor");
|
|
break;
|
|
case CPU_AMDAthlon:
|
|
strcat(name,"AMD Athlon processor");
|
|
break;
|
|
case CPU_AMDDuron:
|
|
strcat(name,"AMD Duron processor");
|
|
break;
|
|
case CPU_WinChipC6:
|
|
strcat(name,"IDT WinChip C6 processor");
|
|
break;
|
|
case CPU_WinChip2:
|
|
strcat(name,"IDT WinChip 2 processor");
|
|
break;
|
|
case CPU_UnkIDT:
|
|
strcat(name,"Unknown IDT processor");
|
|
break;
|
|
default:
|
|
strcat(name,"Unknown processor");
|
|
}
|
|
if (CPU_haveMMX())
|
|
strcat(name," with MMX(R)");
|
|
if (CPU_have3DNow())
|
|
strcat(name,", 3DNow!(R)");
|
|
if (CPU_haveSSE())
|
|
strcat(name,", SSE(R)");
|
|
return name;
|
|
#else
|
|
return "Unknown";
|
|
#endif
|
|
}
|