// gcc -o cpuid cpuid.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpuid.h"

inline void cpuid_vendor(char* vendor)
{
	asm("movl $0,%%eax;"
	    "cpuid;"
	    "movl %%ebx, (%0);"
	    "movl %%edx, 4(%0);"
	    "movl %%ecx, 8(%0);"
	    :
	    :"r" (vendor)
	    :"%eax","%ebx","%ecx","%edx"
	);
	vendor[12] = '\0';
}

inline int cpuid_support_extended()
{
	register int max;
	asm("movl $0x80000000,%%eax;"
	    "cpuid;"
	    :"=a" (max)
	    :
	    :"%ebx","%ecx","%edx"
	);
	if(max > 0x80000000)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

inline void cpuid_info(cpu_info_t* info,cpu_caps_t* caps)
{
	asm("movl $1,%%eax;"
	    "cpuid;"
	    "movl %%eax, (%0);"
	    "movl %%edx, (%1);"
	    "movl %%ecx, 4(%1);"
	    :
	    :"r" (info), "r" (caps)
	    :"%eax","%ebx","%ecx","%edx"	    
	);
}

inline void cpuid_psn(cpu_psn_t* psn)
{
	asm("movl $3,%%eax;"
	    "cpuid;"
	    "movl %%eax, (%0);"
	    "movl %%ebx, 4(%0);"
	    "movl %%ecx, 8(%0);"
	    "movl %%edx, 12(%0);"
	    :
	    :"r" (psn)
	    :"%eax","%ebx","%ecx","%edx"
	);
}

inline void cpuid_cpuname(char* name)
{
	asm("movl $0x80000002, %%eax;"
	    "cpuid;"
	    "movl %%eax,(%0);"
	    "movl %%ebx,4(%0);"
	    "movl %%ecx,8(%0);"
	    "movl %%edx,12(%0);"
	    "movl $0x80000003, %%eax;"
	    "cpuid;"
	    "movl %%eax,16(%0);"
	    "movl %%ebx,20(%0);"
	    "movl %%ecx,24(%0);"
	    "movl %%edx,28(%0);"
	    "movl $0x80000004, %%eax;"
	    "cpuid;"
	    "movl %%eax,32(%0);"
	    "movl %%ebx,36(%0);"
	    "movl %%ecx,40(%0);"
	    "movl %%edx,44(%0);"
	    :
	    :"r" (name)
	    :"%eax","%ebx","%ecx","%edx"
	);
}

int cpuid_cap(cpu_caps_t caps,unsigned int cap)
{
	if(cap > 31)
	{
		cap -= 32;
		return (caps.h & (1 << cap)) != 0;
	}
	else
	{
		return (caps.l & (1 << cap)) != 0;
	}
}

int _WinMain(void)
{
	return main();
}

int main(void)
{
	char vendor[13];
	char name[48];
	cpu_info_t info;
	cpu_caps_t caps;
	cpu_psn_t psn;

	cpuid_vendor(vendor);
	cpuid_info(&info,&caps);
	if(cpuid_support_extended())
	{
		cpuid_cpuname(name);
		printf("Processor: %s\n",name);
	}
	else
	{
		printf("Processor name not supported\n");
	}
	printf("Vendor: %s\n",vendor);
	printf("Stepping: %i\n",info.stepping);
	printf("Model: %i\n",info.model);
	printf("Family: %i\n",info.family);
	if(cpuid_cap(caps,CAP_PSN))
	{
		cpuid_psn(&psn);
		printf("Processor Serial Number:%x-%x-%x-%x\n",psn.a,psn.b,psn.c,psn.d);
	}
	else
	{
		printf("Processor Serial Number not supported\n");
	}	
	printf("MMX: %i, SSE: %i, SSE2: %i, SSE3: %i, SSSE3: %i, SSE4.1: %i, SSE4.2: %i, AVX: %i\nCFLUSH: %i\n",cpuid_cap(caps,CAP_MMX),cpuid_cap(caps,CAP_SSE),cpuid_cap(caps,CAP_SSE2),cpuid_cap(caps,CAP_SSE3),cpuid_cap(caps,CAP_SSSE3),cpuid_cap(caps,CAP_SSE41),cpuid_cap(caps,CAP_SSE42),cpuid_cap(caps,CAP_AVX),cpuid_cap(caps,CAP_CLFL));
	return 0;
}


