/*
								+--------------------------------+
								|                                |
								|    ***  CPU-Id wrapper  ***    |
								|                                |
								|  Copyright © -tHE SWINe- 2010  |
								|                                |
								|            CPUId.h             |
								|                                |
								+--------------------------------+
*/

#pragma once
#ifndef __CPUID_WRAPPER_INCLUDED
#define __CPUID_WRAPPER_INCLUDED

/**
 *	@file low/CPUId.h
 *	@brief CPU-Id wrapper
 *	@date 2010
 *	@author -tHE SWINe-
 */

#include "../Integer.h"

/**
 *	@def __HAVE_INTRINSICS
 *	@brief if defined, will rely on the __cpuid intrinsic
 *	@note CPUId64.asm must be compiled as well to work on x64 (windows) target,
 *		in case the intrinsics are not available. Otherwise it is not needed.
 */
#define __HAVE_INTRINSICS

/**
 *	@brief enables platform-independent access to CPUID flags
 *
 *	@note This was tested on Linux (g++ 4.6.4, CentOS 6.5 x64 / g++ 4.6.3,
 *		Ubuntu 12.04.4 LTS / g++ 4.4.6, bullx Linux 6.3),
 *		Solaris (g++ 3.4.3, SunOS 5.11) and BSD (g++ 4.2.1, FreeBSD-9.2-64bit).
 *		And of course on Windows (MSVC 6.0, MSVC 2008, WinXP, WinXP x64).
 */
class CCPU_Id {
protected:
	bool m_b_supported; /**< @brief cpuid support flag */ 
	char m_p_s_vendor[13]; /**< @brief vendor name */
	char m_p_s_brand[49]; /**< @brief brand name */
	uint32_t m_n_ext_fflags; /**< @brief extended flags */
	uint32_t m_n_info_bits; /**< @brief info bits */
	uint32_t m_n_feature_bits; /**< @brief feature bits */
	uint32_t m_p_feature_bits[2]; /**< @brief extended feature bits */

public:
	/**
	 *	@brief default constructor
	 *
	 *	Determines whether is the CPUID instruction supported, and if it is reads the flags.
	 *
	 *	@note Call b_Supported() to see if the CPUID instruction is supported.
	 */
	CCPU_Id();

	/**
	 *	@brief determinew whether is the CPUID instruction supported
	 *
	 *	@return Returns true if CPUID is supported, otherwise returns false.
	 *
	 *	@note In case CPUID is not suppported, results of any other
	 *		functions in this class are undefined.
	 */
	bool b_Supported() const;

	/**
	 *	@brief calls the CPUID instruction
	 *
	 *	@param[in] n_level is index of information type to retrieve
	 *	@param[out] r_n_eax is contents of eax register
	 *	@param[out] r_n_ebx is contents of ebx register
	 *	@param[out] r_n_ecx is contents of ecx register
	 *	@param[out] r_n_edx is contents of edx register
	 */
	static void cpuid(uint32_t n_level, uint32_t &r_n_eax,
		uint32_t &r_n_ebx, uint32_t &r_n_ecx, uint32_t &r_n_edx);

	/**
	 *	@brief gets CPU vendor string
	 *	@return Returns pointer to a null-terminated string, containing CPU vendor name.
	 *	@note The string is as returned by the CPU and it
	 *		may contain some leading or trailing whitespace.
	 */
	const char *p_s_Vendor() const;

	/**
	 *	@brief gets CPU brand string
	 *	@return Returns pointer to a null-terminated string, containing CPU brand name.
	 *	@note The string is as returned by the CPU and it
	 *		may contain some leading or trailing whitespace.
	 */
	const char *p_s_Brand() const;

	/**
	 *	@brief gets feature bits
	 *	@return Returns feature bits (eax after cpuid 0x01).
	 */
	int n_Feature_Bits() const;

	/**
	 *	@brief gets bit range of the feature bits
	 *
	 *	@param[in] n_last_bit is zero-based index of the first bit to return
	 *	@param[in] n_first_bit is zero-based index of the last bit (inclusive) to return
	 *
	 *	@return Returns the selected bits (part of eax after cpuid 0x01).
	 */
	int n_Feature_Bits(int n_first_bit, int n_last_bit) const;

	/**
	 *	@brief gets stepping number
	 *	@return Returns the stepping number.
	 */
	int n_Stepping() const;

	/**
	 *	@brief gets model number
	 *	@return Returns the model number.
	 */
	int n_Model() const;

	/**
	 *	@brief gets family number
	 *	@return Returns the family number.
	 */
	int n_Family() const;

	/**
	 *	@brief gets type number
	 *	@return Returns the type number.
	 */
	int n_Type() const;

	/**
	 *	@brief gets feature flags
	 *	@return Returns feature flags (ecx after cpuid 0x01).
	 */
	int n_FeatureFlags_C() const;

	/**
	 *	@brief gets feature flags
	 *	@return Returns feature flags (edx after cpuid 0x01).
	 */
	int n_FeatureFlags_D() const;

	/**
	 *	@brief determines whether MMX is supported
	 *	@return Returns true if MMX is supported, otherwise returns false.
	 */
	bool b_Have_MMX() const;

	/**
	 *	@brief determines whether 3DNow! is supported
	 *	@return Returns true if 3DNow! is supported, otherwise returns false.
	 */
	bool b_Have_3DNow() const;

	/**
	 *	@brief determines whether 3DNow!+ is supported
	 *	@return Returns true if 3DNow!+ is supported, otherwise returns false.
	 */
	bool b_Have_3DNow_Plus() const;

	/**
	 *	@brief determines whether SSE is supported
	 *	@return Returns true if SSE is supported, otherwise returns false.
	 */
	bool b_Have_SSE() const;

	/**
	 *	@brief determines whether SSE2 is supported
	 *	@return Returns true if SSE2 is supported, otherwise returns false.
	 */
	bool b_Have_SSE2() const;

	/**
	 *	@brief determines whether SSE3 is supported
	 *	@return Returns true if SSE3 is supported, otherwise returns false.
	 */
	bool b_Have_SSE3() const;

	/**
	 *	@brief determines whether SSSE3 is supported
	 *	@return Returns true if SSSE3 is supported, otherwise returns false.
	 */
	bool b_Have_SSSE3() const;

	/**
	 *	@brief determines whether SSE4a is supported
	 *	@return Returns true if SSE4a is supported, otherwise returns false.
     *	@note SSE4a is AMD's instruction set, unrelated to Intel's SSE4.
	 */
	bool b_Have_SSE4a() const;

	/**
	 *	@brief determines whether SSE4.1 is supported
	 *	@return Returns true if SSE4.1 is supported, otherwise returns false.
	 */
	bool b_Have_SSE4_1() const;

	/**
	 *	@brief determines whether SSE4.2 is supported
	 *	@return Returns true if SSE4.2 is supported, otherwise returns false.
	 */
	bool b_Have_SSE4_2() const;

	/**
	 *	@brief determines whether AVX-256 is supported
	 *	@return Returns true if AVX-256 is supported, otherwise returns false.
	 */
	bool b_Have_AVX() const;
};

#endif // !__CPUID_WRAPPER_INCLUDED
