#include"CCPUID.h"
#include"CString.h"
#include"../Setup/Win32.h"

namespace Maid
{
	namespace CCPUID
	{

	/*!
	 	@class CCPUID CCPUID.h
	 	@brief CPUの演算能力を調べるクラス
	 */


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! CPUID命令が使えるかを調べる
/*!
	@return	CPUID命令が使えるならtrue
 			使えないならfalse
 */
bool IsCPUID()
{
	bool bRet;
	unt32 dwFlag1, dwFlag2;
	_asm{
			pushfd;
			pop		EAX
			mov		dwFlag1,	EAX
			xor		EAX,		0x00200000
			push	EAX
			popfd
			pushfd
			pop		EAX
			mov		dwFlag2,	EAX
		}

    if ( dwFlag1 == dwFlag2)	{bRet = false;}// CPUID命令使用不可
	else						{bRet = true; }// CPUID命令使用可

	return bRet;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! CPUID 命令を呼んで、能力を取得する
/*!
 	ＥＡＸレジスタに、指定された値をセットし、CPUID命令を呼ぶ
 
 	@param  SetEAX		[i ]	ＥＡＸに設定する値
 	@param  retEAX		[ o]	取得後のＥＡＸレジスタの値
 	@param  retEBX		[ o]	取得後のＥＢＸレジスタの値
 	@param  retECX		[ o]	取得後のＥＣＸレジスタの値
 	@param  retEDX		[ o]	取得後のＥＤＸレジスタの値
 
	@return	関数の成功でTRUE
 			関数の失敗でFALSE
 */
bool GetCPUID( unt32 SetEAX, unt32& retEAX, unt32& retEBX, unt32& retECX, unt32& retEDX )
{
	//CPUID命令が使えなかったらFALSE
	if( !IsCPUID() ) { return false; }

	unt32 tmpEAX, tmpEBX, tmpECX, tmpEDX;

	_asm{
			mov		EAX,	SetEAX
			cpuid
			mov		tmpEAX,	EAX
			mov		tmpEBX,	EBX
			mov		tmpECX,	ECX
			mov		tmpEDX,	EDX
		}
	retEAX = tmpEAX;
	retEBX = tmpEBX;
	retECX = tmpECX;
	retEDX = tmpEDX;

	return true;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! CPUの特殊命令が使えるかどうかを調べる
/*!
 
 	@param  dwFunction		[i ]	調べる命令
 	@param  IsAMD			[i ]	AMD系の特殊命令を調べるか（デフォルトでＦＡＬＳＥ）
 
	@return	関数の成功でTRUE
 			関数の失敗でFALSE
 */
bool IsCPUIDFunction( unt32 dwFunction, bool IsAMD )
{
	unt32	EAX, EBX, ECX, EDX;

	unt32 SetEAX = IsAMD? 0x80000001 : 1;

	if ( !GetCPUID( SetEAX, EAX, EBX, ECX, EDX ) ) { return false; }

	return IsFlag( EDX, dwFunction );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! CPUのクロックを測る
/*!
 	RDTSC命令を使って動作周波数(単位Hz)を測定する
 	４Ｇ以上は計れません
 
    @return	成功したらクロック数
 			失敗したら０(==FALSE)
 */
unt32 GetCPUClock()
{
	if( !IsCPUIDFunction( CPUID_RDTSC ) ) { return false; }

	unt32 EAX1, EAX2;

	_asm{
			rdtsc
			mov		EAX1,   eax
		}

	::Sleep(1000);// 一秒スリープ

	_asm{
			rdtsc
			mov		EAX2,   eax
		}

	return EAX2 - EAX1;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 現在のクロックカウンタを取得する
/*!
 	RDTSC命令を使って値を求める
 	
 
 	@param  Over32		[ o]	４Ｇ以上の値
 	@param  Less32		[ o]	４Ｇ以下の値
 
	@return	成功したらTRUE
 			失敗したらFALSE
 */
bool GetRDTSC( unt32& Over32, unt32& Less32 )
{
	if( !IsCPUIDFunction( CPUID_RDTSC ) ) { return false; }

	Over32 = 0;
	Less32 = 0;
	unt32 EAX1, EDX1;

	_asm{
			rdtsc
			mov		EAX1,   eax
			mov		EDX1,   edx
		}

	Over32 = EDX1;
	Less32 = EAX1;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! CPUの製造メーカー名を調べる
/*!
 	
	@return	成功したらメーカー名
 			失敗したらＮＵＬＬ文字
 */
mstring	GetCPUName()
{
	unt32 reg[4];

	if( !GetCPUID( 0, reg[0], reg[1], reg[2], reg[3] ) ) { return false; }

	MySTL::string str;
	str.resize( 12 );

	char* pHead = const_cast<char*>(str.c_str());

	::memcpy( pHead, &reg[1], 12 );

	return CString::ConvertSJIStoMAID(str);
}

	bool IsCPUMMX()		{ return IsCPUIDFunction( CPUID_MMX		); }//!< MMX 命令が使えるか
	bool IsCPUSSE()		{ return IsCPUIDFunction( CPUID_SSE		); }//!< SSE 命令が使えるか
	bool IsCPUSSE2()	{ return IsCPUIDFunction( CPUID_SSE2	); }//!< SSE2 命令が使えるか
	bool IsCPU3DNow()	{ return IsCPUIDFunction( CPUID_3DNOW, true	); }//!< 3DNow! 命令が使えるか
	bool IsCPUEx3DNow()	{ return IsCPUIDFunction( CPUID_EX3DNOW,true); }//!< エンハンスド 3DNow! 命令が使えるか


}
}
//	正確にはこっちを調べること
// http://support.intel.co.jp/jp/support/processors/procid/cpuid/appnote.htm

////////////////////////////////////////////////////////////////////////////////
// CPUID命令の使い方
// ＥＡＸレジスタに、機能番号をセットしCPUID命令を呼びます。
// 得られる命令は、ＥＡＸ／ＥＢＸ／ＥＣＸ／ＥＤＸレジスタに格納されます。
//
// (EAX = 0)
//     EAX : 使用できる機能番号の上限
//     EBX : VenderID 1- 4  先頭４文字
//     ECX : VenderID 9-12  終端４文字
//     EDX : VenderID 5- 8  中央４文字
//
//           <VenderID EBX-EDX-ECX>
//           Intel = "GenuineIntel"
//           AMD   = "AuthenticAMD"
//           Cyrix = "CyrixInstead"
//           IDT   = "CentaurHauls"
//           RISE  = "RiseRiseRise"
//
//
// (EAX = 1)
//     EAX : CPUのバージョン情報
//     EBX : (Reserved)
//     ECX : (Reserved)
//     EDX : 使用出来る機能の情報
//
//           <CPUのバージョン情報 EAX>
//           0000:0000:0000:0000:00TT:FFFF:MMMM:SSSS
//            T:Processor Type 
//             オリジナルOEMプロセッサ／OverDrive／デュアルプロセッサ
//            F:Family 
//             i386/i486/Pentium/PentiumPro/PentiumII 
//            M:Model
//             プロセッサファミリモデル。 
//            S:Stepping
//             モデルのリビジョン番号。 
//            注：ModelとSteppingには規則はない。（任意割り当て）
//
//                CPU-NAME  (N:Non-Support-CPUID), Type, Family, Model, Stepping
//           Intel(GenuineIntel)                -,    -,      -,     -,        -
//                i486DX                        N,    0,      4,     0,        X
//                i486DX                        N,    0,      4,     1,        X
//                i486SX                        N,    0,      4,     2,        X
//                i487                          N,    0,      4,     3,        X
//                DX2                           N,    0,      4,     3,        X
//                DX2 OverDrive                 N,    0,      4,     3,        X
//                i486SL                        N,    0,      4,     4,        X
//                i486SL                         ,    0,      4,     4,       3-
//                SX2                           N,    0,      4,     5,        X
//                Writeback Enhanced DX2        N,    0,      4,     7,        X
//                Writeback Enhanced DX2         ,    0,      4,     7,       3-
//                DX4                           N,    0,      4,     8,        X
//                DX4                            ,    0,      4,     8,       3-
//                DX4 OverDrive                 N,    0,      4,     8,        X
//                DX4 OverDrive                  ,    0,      4,     8,       3-
//                DX4 OverDrive                 N,    1,      4,     8,        X
//                DX4 OverDrive                  ,    1,      4,     8,       3-
//                Pentium 60/66                  ,    0,      5,     1,        X
//                Pentium 75/90/100/120          ,    0,      5,     2,        X
//                Pentium 133/150/166/200        ,    0,      5,     2,        X
//                Pentium 60/66用 OverDrive      ,    1,      5,     1,        X
//                i486用 Pentium OverDrive       ,    1,      5,     3,        X
//                MMX Pentium 166/200            ,    0,      5,     4,        X
//                Pentium 75/90用 MMX OverDrive  ,    1,      5,     4,        X
//                Pentium 100/120用 MMX OverDrive,    1,      5,     4,        X
//                Pentium 133用 MMX OverDrive    ,    1,      5,     4,        X
//                PentiumPro                     ,    0,      6,     1,        X
//                PentiumII model 3              ,    0,      6,     3,        X
//                PentiumII model 5/Xeon/Celeron ,    0,      6,     5,        X
//                PentiumPro用 OverDrive         ,    1,      6,     3,        X
//           AMD  (AuthenticAMD)                 ,    -,      -,     -,        -
//           Cyrix(CyrixInstead)                 ,    -,      -,     -,        -
//           IDT  (CentaurHauls)                 ,    -,      -,     -,        -
//                WinChip  C6                    ,    0,      5,     4,        1
//                WinChip2 C6-2                  ,    0,      5,     8,        5
//           RISE (RiseRiseRise)                 ,    -,      -,     -,        -
//
//           <使用出来る機能の情報 EDX>
//           Bit00 : On Chip Floting Point Unit
//           Bit01 : Virtual Mode Extentions
//           Bit02 : Debugging Extentions
//           Bit03 : Page Size Extentions
//           Bit04 : Time Stamp Counter
//           Bit05 : RDMSR/WRMSR Instruction
//           Bit06 : Physical Address Extentions
//           Bit07 : Machine Check Exception
//           Bit08 : CMPXCHG8B Instruction
//           Bit09 : On Chip APIC
//           Bit10 : 
//           Bit11 : Fast System Call
//           Bit12 : Memory Type Range Registers
//           Bit13 : PTE Global Flag
//           Bit14 : Machine Check Architecture
//           Bit15 : CMOV Instruction
//           Bit16 : Page Attribute Table
//           Bit17 : 36-bit Page Size Extentions
//           Bit18 : Processor Number
//           Bit23 : MMX Instruction
//           Bit24 : Fast FXSR Instruction
//           Bit25 : Streaming SIMD Instruction
//
//
// (EAX = 2)
//     EAX : CacheとTLBの情報（bit31=1 で、情報無効）(AL=必用呼出回数)
//     EBX : CacheとTLBの情報（bit31=1 で、情報無効）
//     ECX : CacheとTLBの情報（bit31=1 で、情報無効）
//     EDX : CacheとTLBの情報（bit31=1 で、情報無効）
//
//           ALには全ての情報を得るためにCPUID(EAX=2)を呼ぶ回数が格納される。
//     (注意)ＡＭＤ製互換ＣＰＵの場合、(EAX=2)ではキャッシュ情報を得られない。
//           (EAX=0x80000005 L1Cache)と(EAX=0x80000006 L2Cache)を使う。
//
//
// (EAX =0x80000000 )ＡＭＤ製互換ＣＰＵ
//     EAX : 使用できる機能番号の上限(ＡＭＤ製互換ＣＰＵ)
//     EBX : (Reserved)
//     ECX : (Reserved)
//     EDX : (Reserved)
//
// (EAX =0x80000001 )ＡＭＤ製互換ＣＰＵ
//     EAX : CPUのバージョン情報
//     EBX : (Reserved)
//     ECX : (Reserved)
//     EDX : 使用出来る機能の情報
//
// (EAX =0x80000002 )ＡＭＤ製互換ＣＰＵ
//     EAX : CPU名称  1- 4 文字
//     EBX : CPU名称  5- 8 文字
//     ECX : CPU名称  9-12 文字
//     EDX : CPU名称 13-16 文字
//
// (EAX =0x80000003 )ＡＭＤ製互換ＣＰＵ
//     EAX : CPU名称 17-20 文字
//     EBX : CPU名称 21-24 文字
//     ECX : CPU名称 25-28 文字
//     EDX : CPU名称 29-32 文字
//
// (EAX =0x80000004 )ＡＭＤ製互換ＣＰＵ
//     EAX : CPU名称 33-36 文字
//     EBX : CPU名称 37-40 文字
//     ECX : CPU名称 41-44 文字
//     EDX : CPU名称 45-48 文字
//
// (EAX =0x80000005 )ＡＭＤ製互換ＣＰＵ
//     EAX : (Reserved)
//     EBX : TLB情報
//     ECX : L1 Data Cache 情報
//     EDX : L1 Instruction Cache 情報
//
// (EAX =0x80000006 )ＡＭＤ製互換ＣＰＵ
//     EAX : (Reserved)
//     EBX : (Reserved)
//     ECX : L2 Unified Cache 情報
//     EDX : (Reserved)
////////////////////////////////////////////////////////////////////////////////
