概要

現在のCPUではマルチコアやハイパースレッド(HT)が当たり前となっています。より高速に動作させるプログラムを作成するためには、CPU内の物理CPUと論理CPUの関係を知る必要があります。
例えばハイパースレッドをサポートしているCPUで同じ物理CPUに2つのスレッドを割り当るとCPUのリソースを共有するのでパフォーマンスが下がる場合があります。物理CPUに余裕がある場合は、2つのスレッドを別の物理CPUに割り当てを行い、リソースの競合を防ぐことができます。
CPUID命令はAPIC及びx2APICの値はCPUごとに固有の値を返します。
本プログラムは、論理CPU番号がどのパッケージ(ソケット)でどの物理CPUに割り当てられているか取得することができます。
また、CPUIDの実行結果等をcpuid.txtファイルに保存します。
下図のセルのCoreの次の数字がCPUパッケージ内のコア番号 その横の数字がWindowsが割り当てた論理CPU番号です。

下表は、各CPUでの実行結果をまとめたものです。
ローカルAPIC(8bit)の行のPCSはPがパッケージ番号、Cがコア番号、Sはスレッド番号を示し、下位ビット側のビットパターンを示しています。残りの上位ビットはパッケージ番号です。
x2APIC(32bit)の行のPCSはPがパッケージ番号、Cがコア番号、Sはスレッド番号を示し、下位ビット側のビットパターンを示しています。残りの上位ビットはパッケージ番号です。
一番左の列の数字は、Windows上での論理CPU番号です。
論理CPU番号の行の例えば0 1 1等の数字は、左がパッケージ番号、中央がコア番号、右がスレッド番号を示しています。
i3-M370の場合、コア番号が0から2に飛んでいます。コア数を取得する場合、コア番号の最大値+1で取得することができないことを示している。
i7-870、i3-2100、i7-2600の論理CPUに対する物理コアの割り付けが異なっている。他のCPUでは物理コア番号が2個飛びに増えていくが、i7-870等は、スレッド0が論理CPUの若い番号を占め、スレッド1が論理CPUの後半の番号に割り当てられている。これはWindowの処理の違いである。
同じ物理CPUに2つのスレッドを割り付けないようにするためには、この違いを検出して対処する必要がある。
マイクロ アーキテクチャ NetBurst系 Core系 Nehalem系 Sandy Bridge系 Haswell系
CPU名称 Pentium 4 641 Pentium D 945 Celeron 450 Core2 Duo E6320 Core2 Quad Q8200 i7-870 i3-M370 i3-2100 i7-2600 i7-3820 i7-3770 i7-4770 E5-2608v3*2
コード名 Cedar Mill Presler Conroe-L Conroe Yorkfield Lynnfield Arrandale Sandy Bridge Sandy Bridge Sandy Bridge-E Ivy Bridge Haswell Haswell-EP
プロセル 65nm 65nm 2ダイ2コア 65nm 65nm 45nm 2ダイ2コア 45nm 32nm 32nm 32nm 32nm 22nm 22nm 22nm
ローカル APIC CS C - C CC CCCCS CCCCS CCCCS CCCCS CCCCCS CCCCS CCCCS PCCCCS
x2APIC CCCCS CCCCS CCCCS CCCCS CCCCCS CCCCS CCCCS PCCCCS
0 0 0 0 0 0 0 - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1
2 0 2 0 0 2 0 0 2 0 0 0 1 0 2 0 0 1 0 0 1 0 0 1 0 0 1 0
3 0 3 0 0 3 0 0 2 1 0 1 1 0 3 0 0 1 1 0 1 1 0 1 1 0 1 1
4 0 0 1 0 0 1 0 2 0 0 2 0 0 2 0 0 2 0
5 0 1 1 0 1 1 0 2 1 0 2 1 0 2 1 0 2 1
6 0 2 1 0 2 1 0 3 0 0 3 0 0 3 0 0 3 0
7 0 3 1 0 3 1 0 3 1 0 3 1 0 3 1 0 3 1
8 0 4 0
9 0 4 1
10 0 5 0
11 0 5 1
12 1 0 0
13 1 0 1
14 1 1 0
15 1 1 1
16 1 2 0
17 1 2 1
18 1 3 0
19 1 3 1
20 1 4 0
21 1 4 1
22 1 5 0
23 1 5 1

テスト環境

コンパイラ

Visual C++ 2013 Express 32/64bit マルチバイト/UNICODE

実行環境

Windows 7 Enterprise Service Pack 1 64bit(Sandy Bridge-E)
Windows 8.1 Enterprise 64bit(Arrandale)
Intel(R) Core(TM) i3 CPU M 370 @ 2.40GHz
Intel(R) Core(TM) i7-3820 CPU @ 3.60GHz

CPUIDの実行結果からのエミュレーション結果

Pentium4及びCore2Quad等は現在テストできる環境を持ち合わせていないが、CPUIDの実行結果が残っていたのでエミュレーションした。
本プログラムでは、cpuemu.hの該当するCPUに対応するマクロを有効にし実行ファイルを作成するとエミュレーションモードになる。
Intel(R) Pentium(R) 4 CPU 3.20GHz
Intel(R) Pentium(R) D CPU 3.40GHz
Intel(R) Celeron(R) CPU 450 @ 2.20GHz
Intel(R) Core(TM)2 CPU 6320 @ 1.86GHz
Intel(R) Core(TM)2 Quad CPU Q8200 @ 2.33GHz
Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz
Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz
Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz

CPUの仕様からのエミュレーション結果

CPUの仕様及び同世代のCPUのCPUIDをもとにエミュレーションした。
本プログラムでは、cpuemu.hの該当するCPUに対応するマクロを有効にし実行ファイルを作成するとエミュレーションモードになる。
Intel Xeon E5-2608 v3 @ 2.0GHz デュアルソケット
Intel Xeon E5-2698 v3 @ 2.3GHz デュアルソケット
Intel Xeon E7-4809 v2 @ 1.9GHz クワッドソケット

プログラムソースの概要

cputopology.cpp

CPUクラスのオブジェクトを割り当て・初期化します。初期化時にCPUIDを用いて物理コア等の情報を取得します。

WinMain

ダイアログボックスを表示します。

DlgProc

ダイアログボックスプロシージャーです。
WM_INITDIALOG
ListViewHeader関数によりリストビューのヘッダーを表示します。
putListView関数によりリストビューのセルに表示します。

WM_COMMAND

IDOK
OKボタンをクリックすると発生するメッセージです。
EndDialog APIによりダイアログボックスを終了させます。

ListViewHeader

リストビューのヘッダーを表示します。
ソケット数に応じて列を増やします。

putListView

リストビューに各ソケット毎に、コア数・スレッド数及びコア内のスレッドに対するWindowsが割り当てた論理CPU番号及びコア番号を表示します。

cpu.h

CPU_PKG 構造体

CPUのパッケージの情報を保存しています。
メンバー変数
coreMax:コア数
threadMax:スレッド数
threadvec:CPUのスレッド番号に対する(配列の添え字)Windowsが割り当てた論理CPU番号を保存します。
	CPUのスレッド番号1に対応するWindowsが割り当てた論理CPUを取得する場合 threadvec[1]
corevec:CPUのスレッド番号に対する(配列の添え字)Windowsが割り当てたコア番号を保存します。
	CPUのスレッド番号3に対応するWindowsが割り当てたコア番号を取得する場合 corevec[3]
name:CPUIDで取得したCPUの名称を示す文字列が保存されています。
メンバー関数
short_name:引数で指定した配列にCPUの名称に含まれる複数の連続した空白を削除して保存します。
次にi7-3820でshort_nameの実行前(次の行)と実行結果(実行前の次の行)を示します。
        Intel(R) Core(TM) i7-3820 CPU @ 3.60GHz
Intel(R) Core(TM) i7-3820 CPU @ 3.60GHz
先頭の空白が削除されているのがわかるかと思います。

CPU 構造体

CPUのパッケージを複数個まとめて管理します。
メンバー変数
cpu_pkg:複数のCPU_PKG構造体を保存しています。
pkgMax:システムのパッケージ数
lCpuMax:システムの論理CPU数
メンバー関数
コンストラクタ
get関数を呼び出して、システムのCPUの情報を取得します。
getPackageMax
物理パッケージ数を返します。

cpu.cpp

CPU:get 関数

GetCPUMax関数により論理CPU数を取得します。
各CPUごとに情報を取得
各CPUに固定してCPUID命令を実行する必要があるので、SetThreadAffinityMask APIを使用します。
スレッド数・コア数の情報はCPUによって、割り当てられている位置が異なります。
EAX=0として__cpuid関数を呼び出すことによりCPUID命令がサポートしている範囲(EAXに最大値が得られる)を調べます。__cpuid関数の引数は配列でありレジスタ名との対応が面倒なので、共用体REG32を定義しています。
EAXが11以上をサポートしている場合、x2APICから取得します。11未満の場合は、APICから取得します。
x2APIC
スレッド数・コア数の情報に割り当てられたビット数はCPUによって異なります。
EAX=11,ECX=0として__cpuidex関数を呼び出すとEAX[4~0]にSMTのビット幅が得られます。32bitが全部1の値をビット幅で左シフトし、その値を反転させ、EDXとANDをとると、SMT(コア内のスレッド番号)が得られます。
EAX=11,ECX=1として__cpuidex関数を呼び出すとEAX[4~0]にコアのビット幅が得られます。32bitが全部1の値をSMTとコアを加算したビット幅で左シフトし、その値を反転させ、EDXとANDをとり左シフトした分を右シフトすると、コア番号が得られます。
パッケージ番号はコア番号より上位側に割り当てられています。右シフトによりパッケージ番号を得られます。
APIC
スレッド数・コア数の情報に割り当てられたビット数はCPUによって異なります。
EAX=1として__cpuid関数を呼び出します。EBX[31~24]にAPICが取得できます。
EBX[31~16]に論理CPU数が取得できます。
EAX=4,ECX=0として__cpuidex関数を呼び出します。
SMTのビット幅は論理CPUのビット数/(EAX[31~26]+1)のビット数で得られます。
コアのビット幅は、EAX[31~26]+1)のビット数です。
これらの情報よりAPICからx2APICと同じ要領でパッケージ数、コア数、SMT数を取得できます。
parse
Windowsが割り当てる論理CPU番号とCPUのスレッド順とは異なる場合があるので、Windows上の論理CPU・パッケージ・コア・スレッドの情報をDWORDに変換して、qsort関数で並び変えます。
コア数は、最大のコア番号と異なる場合があるので、同じ値でないコア番号の数をカウントします。

各CPUのエミュレーション用cpuid関数

cpuidemu.hで各CPU名のマクロを有効にすると対応するCPUのエミュレーション関数が有効になります。
以下の入力のみに対するCPUID命令が返す値をエミュレーションします。
EAX=0,1,0x80000000,0x80000002,0x80000003,0x80000004
EAX=4,ECX=0~1 又は EBX=11,ECX=0~1

ソースコード

cputopology.cpp

//	各論理CPUがどの物理パッケージ、どのコアに属しているか表示

#include <windows.h>
#include <commctrl.h>
#include <intrin.h>
#include <stdio.h>
#include <tchar.h>
#include "cpu.h"
#include "resource.h"

#pragma comment(lib,"comctl32.lib")

//	ダイアログボックスプロシージャー
LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);

//	リストビューヘッダー定義
void ListViewHeader(HWND hList, int pkgMax);

//	リストビュー表示
void putListView(HWND hList);

HINSTANCE hInst;

CPU cpu;

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow){

	::hInst = hCurInst;
	//	ダイアログボックスの表示
	DialogBox(hCurInst, TEXT("DLG1"), 0, (DLGPROC)DlgProc);

	return 0;
}

//	ダイアログボックスプロシージャー

LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
	static HWND imgH;
	switch (msg) {
	case WM_INITDIALOG:
		ListViewHeader(GetDlgItem(hDlg, IDC_LISTVIEW100), cpu.getPackageMax());
		putListView(GetDlgItem(hDlg, IDC_LISTVIEW100));
		return TRUE;
	case WM_COMMAND:
		switch (LOWORD(wParam)){
		case IDOK:
			EndDialog(hDlg, TRUE);
			return TRUE;
		default:
			return FALSE;
		}
	default:
		return FALSE;
	}
	return TRUE;
}

//	リストビューヘッダー定義

void ListViewHeader(HWND hList, int pkgMax){
	LV_COLUMN lvcol;
	TCHAR buf[64];
	lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvcol.fmt = LVCFMT_LEFT;
	lvcol.cx = 80;
	lvcol.pszText = _TEXT("名称");
	lvcol.iSubItem = 0;
	ListView_InsertColumn(hList, 0, &lvcol);
	for (int n = 1; n <= pkgMax; n++){
		_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("ソケット%i"), n - 1);
		lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
		lvcol.fmt = LVCFMT_LEFT;
		lvcol.cx = 80;
		lvcol.pszText = buf;
		lvcol.iSubItem = n;
		ListView_InsertColumn(hList, n, &lvcol);
	}
}

//	リストビュー表示

void putListView(HWND hList){
	LV_ITEM item;
	int n;
	TCHAR buf[64];

	item.mask = LVIF_TEXT | LVIF_PARAM;
	item.pszText = _TEXT("名称");
	item.iItem = 0;
	item.iSubItem = 0;
	item.lParam = 0;
	ListView_InsertItem(hList, &item);

	item.mask = LVIF_TEXT | LVIF_PARAM;
	item.pszText = _TEXT("コア数");
	item.iItem = 1;
	item.iSubItem = 0;
	item.lParam = 1;
	ListView_InsertItem(hList, &item);

	item.mask = LVIF_TEXT | LVIF_PARAM;
	item.pszText = _TEXT("スレッド数");
	item.iItem = 2;
	item.iSubItem = 0;
	item.lParam = 2;
	ListView_InsertItem(hList, &item);

	int threadMaxs = 0;

	for (n = 0; n < cpu.getPackageMax(); n++){
		if (threadMaxs < cpu.cpu_pkg[n].threadMax)
			threadMaxs = cpu.cpu_pkg[n].threadMax;
	}
	for (n = 0; n < threadMaxs; n++){
		_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("Thread%i"), n);
		item.mask = LVIF_TEXT | LVIF_PARAM;
		item.pszText = buf;
		item.iItem = 3 + n;
		item.iSubItem = 0;
		item.lParam = 3 + n;
		ListView_InsertItem(hList, &item);
	}
	for (n = 0; n < cpu.getPackageMax(); n++){
		item.mask = LVIF_TEXT;
		item.pszText = cpu.cpu_pkg[n].short_name(buf);
		item.iItem = 0;
		item.iSubItem = n + 1;
		ListView_SetItem(hList, &item);

		_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%i"), cpu.cpu_pkg[n].coreMax);
		item.mask = LVIF_TEXT;
		item.pszText = buf;
		item.iItem = 1;
		item.iSubItem = n + 1;
		ListView_SetItem(hList, &item);

		_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%i"), cpu.cpu_pkg[n].threadMax);
		item.mask = LVIF_TEXT;
		item.pszText = buf;
		item.iItem = 2;
		item.iSubItem = n + 1;
		ListView_SetItem(hList, &item);

		for (int u = 0; u < cpu.cpu_pkg[n].threadMax; u++){
			_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("Core%0.2i %0.2i"), cpu.cpu_pkg[n].corevec[u], cpu.cpu_pkg[n].threadvec[u]);
			item.mask = LVIF_TEXT;
			item.pszText = buf;
			item.iItem = 3 + u;
			item.iSubItem = 1 + n;
			ListView_SetItem(hList, &item);
		}
	}
}

cpu.h

#ifndef CPU_H

#define CPU_H 0x01


//	論理CPU数を取得する
int GetCPUMax(void);
void GetCpuName(TCHAR* cpuname);
//	必要なbit数を取得する

int bit_count(DWORD d);

union REG32{
	int vec[4];
	struct {
		DWORD eax, ebx, ecx, edx;
	};
};

struct CPU_PKG{
	//	コアの大きさ
	int cx;
	int cy;
	//	パッケージとコアの距離
	int px;
	int py;

	int coreMax;	//	コア数
	int threadMax;	//	スレッド数

	int* threadvec;	//	CPU→論理CPU番号
	int* corevec;	//	CPU→コア
	TCHAR* name;
	void DrawOwn(HDC hdc, int sx, int sy, int cpuNum);	// 1個の物理CPU
	void Draw(HDC hdc, int sx, int sy, int* ex, int* ey);
	CPU_PKG(){
		cx = 64;
		cy = 32;
		px = 8;
		py = 16;
	}
	~CPU_PKG(){
		delete name;
	}
	TCHAR* short_name(TCHAR* sname){	//	CPU名称の複数の空白を詰める
		TCHAR* src = name;
		TCHAR* dtc = sname;
		while (*src == _T(' '))	//	先頭の空白を削除
			src++;
		int c=0;
		while (*src){
			if (*src == _T(' ') && c == _T(' ')){


			}else{
				*dtc++ = *src;

			}
			c = *src;
			++src;
		}

		*dtc = _T('\0');
		return sname;
	}
};

struct CPU{
	CPU_PKG* cpu_pkg;
	int pkgMax;
	DWORD* smt, *core, *pkg;
	DWORD* temp;
	int lCpuMax;
	FILE* fp;
	CPU();
	~CPU();
	void Draw(HDC hdc, int sx, int sy);
	int getPackageMax(void);	//	物理パッケージ数(ソケット)を取得
	union CMP_TEMP{
		struct {
			char num;
			char smt;
			char core;
			char pkg;
		};
		int dword;

	};
	void parse(void);
	friend int dwordcmp(const void *dtcp, const void* srcp);
	void get(void);
};

#include "cpuemu.h"


#endif

cpu.cpp

#include <windows.h>
#include <stdio.h>
#include <intrin.h>
#include <tchar.h>

#define CPU_CPP 0x01

#include "cpu.h"


CPU::CPU(){
	smt = core = pkg = 0;
	temp = 0;
	_tfopen_s(&fp, _TEXT("cpuid.txt"), _TEXT("w,ccs=UNICODE"));
	get();
	fclose(fp);
}
CPU::~CPU(){
	delete[] smt;
	delete[] core;
	delete[] pkg;
	delete[] temp;
}

int CPU::getPackageMax(void){	//	物理パッケージ数(ソケット)を取得
	return pkgMax;
}
void CPU::parse(void){
	int cMax = 0;
	int n;

	for (n = 0; n < lCpuMax; n++){
		CMP_TEMP t;
		t.pkg = (unsigned char)pkg[n];
		t.core = (unsigned char)core[n];
		t.smt = (unsigned char)smt[n];
		t.num = n;
		temp[n] = t.dword;

	}
	qsort(temp, lCpuMax, sizeof(temp[0]), dwordcmp);

	int coreCount = 0;
	int smtCount = 0;
	int pkgCount = 0;

	int rePkg = 0;
	int reCore = -1;
	int reSmt = -1;
	int threadCount = 0;
	CMP_TEMP t = *((CMP_TEMP*)(&temp[lCpuMax - 1]));
	pkgMax = t.pkg + 1;
	cpu_pkg = new CPU_PKG[pkgMax];
	for (n = 0; n < lCpuMax; n++){

		t.dword = temp[n];
		if (rePkg != t.pkg){
			CPU_PKG c = cpu_pkg[pkgCount];
			cpu_pkg[pkgCount].coreMax = coreCount;
			cpu_pkg[pkgCount].threadMax = threadCount;
			threadCount = 0;
			++pkgCount;
			coreCount = 0;
			smtCount = 0;
		}
		if (reSmt != t.smt)
			++smtCount;
		if (reCore != t.core)
			++coreCount;
		++threadCount;
		rePkg = t.pkg;
		reCore = t.core;
		reSmt = t.smt;
	}
	cpu_pkg[pkgCount].coreMax = coreCount;
	cpu_pkg[pkgCount].threadMax = threadCount;

	for (n = 0; n < pkgMax; n++){
		int num = cpu_pkg[n].threadMax;
		cpu_pkg[n].threadvec = new int[cpu_pkg[n].threadMax];
		cpu_pkg[n].corevec = new int[cpu_pkg[n].threadMax];
	}
	int u = 0;
	rePkg = 0;
	for (n = 0; n < lCpuMax; n++){
		CMP_TEMP t;
		t.dword = temp[n];
		if (rePkg != t.pkg){
			u = 0;
		}
		cpu_pkg[t.pkg].threadvec[u] = t.num;
		cpu_pkg[t.pkg].corevec[u] = t.core;
		++u;
		rePkg = t.pkg;
	}

	TCHAR buf[128];

	for (n = 0; n < pkgMax; n++){
		HANDLE h;
		h = GetCurrentThread();
		SetThreadAffinityMask(h, 1 << cpu_pkg[n].threadvec[0]);	//	CPUを物理パッケージの最初のコアに固定
		GetCpuName(buf);
		int len = (int)_tcslen(buf);
		cpu_pkg[n].name = new TCHAR[len + 1];
		_tcscpy_s(cpu_pkg[n].name, len + 1, buf);
	}

	_ftprintf(fp, _TEXT("パッケージ コア数 スレッド数 CPU名称\n"));

	for (n = 0; n < pkgMax; n++){
		TCHAR name[64];
		_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%i %i %i %s\n"), n, cpu_pkg[n].coreMax, cpu_pkg[n].threadMax, cpu_pkg[n].short_name(name));
		_ftprintf(fp, buf);
	}

	_ftprintf(fp, _TEXT("パッケージ コア 論理CPU\n"));

	for (n = 0; n < pkgMax; n++){
		for (int u = 0; u < cpu_pkg[n].threadMax; u++){
			_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%i %i %i\n"), n, cpu_pkg[n].corevec[u], cpu_pkg[n].threadvec[u]);
			_ftprintf(fp, buf);
		}
	}
}

int dwordcmp(const void *dtcp, const void* srcp){
	int dtc = *(int*)dtcp;
	int src = *(int*)srcp;
	return dtc - src;

}

void CPU::get(void){
	REG32 reg;
	lCpuMax = GetCPUMax();

	smt = new DWORD[lCpuMax];
	core = new DWORD[lCpuMax];
	pkg = new DWORD[lCpuMax];
	temp = new DWORD[lCpuMax];

	HANDLE h;
	h = GetCurrentThread();
	for (int n = 0; n < lCpuMax; n++){
#ifdef CPU_EMU
		cpunum = n;
#else
		SetThreadAffinityMask(h, 1 << n);	//	CPU0に固定
#endif
		Sleep(1);
		TCHAR cpuname[48];
		TCHAR buf[34];
		DWORD u;
		TCHAR* p = buf + (sizeof(buf) / sizeof(TCHAR)) - 1;
		*p = _T('\0');

		GetCpuName(cpuname);
		_ftprintf(fp, _TEXT("Processor %0.2i %s CPUID\n"), n, cpuname);
		__cpuid(reg.vec, 0x00);
		if (11 <= reg.eax){	//	CPUIDは拡張トポロジをサポート (x2APIC ID)
			__cpuid(reg.vec, 0x01);
			unsigned lapic = ((unsigned)reg.ebx >> 24) & 0xff;
			_ftprintf(fp, _TEXT("\tEAX=0x1 - EBX[31-24]:Local APIC ID %0.2x\n"), lapic);
			__cpuidex(reg.vec, 11, 0);	//	SMT
			DWORD SMT_Select_Mask, SMT_Mask_Width;
			if (((reg.ecx >> 8) & 0xff) == 1){
				SMT_Mask_Width = reg.eax & 0x1f;
				SMT_Select_Mask = ~(0xffffffff << SMT_Mask_Width);
				smt[n] = reg.edx & SMT_Select_Mask;
			}
			else
				smt[n] = 0;
			_ftprintf(fp, _TEXT("\tEAX=0xB ECX=0 - %0.8x %0.8x %0.8x %0.8x\n"), reg.eax, reg.ebx, reg.ecx, reg.edx);
			__cpuidex(reg.vec, 11, 1);	//	Core
			DWORD CorePlus_Mask_Width;
			if (((reg.ecx >> 8) & 0xff) == 2){
				CorePlus_Mask_Width = reg.eax & 0x1f;
				DWORD CoreOnly_Select_Mask = (~(0xffffffff << CorePlus_Mask_Width)) ^ SMT_Select_Mask;
				core[n] = (reg.edx & CoreOnly_Select_Mask) >> SMT_Mask_Width;

				DWORD Pkg_Select_Mask = 0xffffffff << CorePlus_Mask_Width;
				pkg[n] = (reg.edx & Pkg_Select_Mask) >> CorePlus_Mask_Width;
			}
			else{
				core[n] = 0;
				pkg[n] = 0;
			}

			_ftprintf(fp, _TEXT("\tEAX=0xB ECX=1 - %0.8x %0.8x %0.8x %0.8x\n"), reg.eax, reg.ebx, reg.ecx, reg.edx);

			--p;
			for (u = 0; u < SMT_Mask_Width; u++){
				*p = _T('S');
				--p;
			}
			for (u = 0; u < CorePlus_Mask_Width; u++){
				*p = _T('C');
				--p;
			}
			for (; buf<=p; p--){
				*p = _T('P');
			}
			_ftprintf(fp, _TEXT("\tx2APIC %0.8x ビットパターン(P:パッケージ,C:コア,S:SMT)\n\t\tコア %iビット SMT%iビット\n\t\t%s\n"), reg.edx, CorePlus_Mask_Width, SMT_Mask_Width, ++p);

			_ftprintf(fp, _TEXT("Processor %0.2i Packages %0.2i Core %0.2i SMT %0.2i\n\n"), n, pkg[n], core[n], smt[n]);



		}
		else{	// Pentium4 PentiumD Core2Duo Core2QuadはEAX=11をサポートしていないのでローカルAPICから取得
			__cpuid(reg.vec, 0x01);
			unsigned lapic = ((unsigned)reg.ebx >> 24) & 0xff;
			_ftprintf(fp, _TEXT("\tEAX=0x1 - %0.8x %0.8x %0.8x %0.8x\n"), reg.eax, reg.ebx, reg.ecx, reg.edx);
			_ftprintf(fp, _TEXT("\tEAX=0x1 - EBX[31-24]:Local APIC ID %0.2x\n"), lapic);
			unsigned lCpu = (reg.ebx >> 16) & 0xff;	//	論理CPU数

			__cpuidex(reg.vec, 0x04, 0x00);
			_ftprintf(fp, _TEXT("\tEAX=0x4 ECX=0 - %0.8x %0.8x %0.8x %0.8x\n"), reg.eax, reg.ebx, reg.ecx, reg.edx);
			unsigned temp = (reg.eax >> 26) & 0x3f;
			unsigned d = 0;
			if (lCpu)
				d = lapic / (lCpu + 1);


			DWORD SMT_Mask_Width = bit_count(lCpu) / (temp + 1);
			DWORD SMT_Select_Mask = ~(0xffffffff << SMT_Mask_Width);
			smt[n] = lapic & SMT_Select_Mask;
			DWORD CoreOnly_Mask_Width = bit_count(temp + 1);
			DWORD CoreOnly_Select_Mask = (~(0xffffffff << (CoreOnly_Mask_Width + SMT_Mask_Width))) ^ SMT_Select_Mask;
			core[n] = (lapic & CoreOnly_Select_Mask) >> SMT_Mask_Width;

			DWORD CorePlus_Mask_Width = CoreOnly_Mask_Width + SMT_Mask_Width;
			DWORD Pkg_Select_Mask = 0xffffffff << CorePlus_Mask_Width;
			pkg[n] = (lapic & Pkg_Select_Mask) >> CorePlus_Mask_Width;

			--p;
			for (u = 0; u < SMT_Mask_Width; u++){
				*p = _T('S');
				--p;
			}
			for (u = 0; u < CorePlus_Mask_Width; u++){
				*p = _T('C');
				--p;
			}
			for (; buf+(sizeof(buf)/sizeof(TCHAR))-1-8 <= p; p--){
				*p = _T('P');
			}
			_ftprintf(fp, _TEXT("\tAPIC %0.2x ビットパターン(P:パッケージ,C:コア,S:SMT)\n\t\tコア %iビット SMT%iビット\n\t\t%s\n"), lapic, CorePlus_Mask_Width, SMT_Mask_Width, ++p);

			_ftprintf(fp, _TEXT("Processor %0.2i Packages %0.2i Core %0.2i SMT %0.2i\n\n"), n, pkg[n], core[n], smt[n]);


		}
	}
	parse();
}


int GetCPUMax(void){
#ifdef CPU_EMU
	return CPU_EMU;
#else
	SYSTEM_INFO sys;
	GetSystemInfo(&sys);
	return sys.dwNumberOfProcessors;
#endif
}

void GetCpuName(TCHAR* cpuname){
	REG32 reg[3];
	__cpuid(reg[0].vec, 0x80000000);
	if (0x80000002 <= reg[0].eax){	//	プロセッサブランド文字列の取得が可能である
		__cpuid(reg[0].vec, 0x80000002);
		__cpuid(reg[1].vec, 0x80000003);
		__cpuid(reg[2].vec, 0x80000004);
		char* p = (char*)&reg;
		for (int n = 0; n < 4 * 4 * 3; n++){
			cpuname[n] = *p++;
		}
	}
	else
		cpuname[0] = 0;
}

//	必要なbit数を取得する

int bit_count(DWORD d){
	//	dに必要なbit数を算定する
	int bit = 0;
	DWORD mask = 1;
	for (int b = 0; b<32; b++){
		if (mask >= d){
			bit = b;
			break;
		}
		mask = mask << 1;
	}
	return bit;
}


#ifdef P4_EMU
void emu_p4_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x00000006;
		reg.ebx = 0x756E6547;
		reg.ecx = 0x6C65746E;
		reg.edx = 0x49656E69;
		break;
	case 1:
		reg.eax = 0x00000F62;
		reg.ebx = 0x00020800 + (cpunum << 24);
		reg.ecx = 0x0000E41D;
		reg.edx = 0xBFEBFBFF;
		break;
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;
		break;
	case 0x80000002:
		reg.eax = 0x20202020; reg.ebx = 0x20202020; reg.ecx = 0x20202020; reg.edx = 0x6E492020;

		break;
	case 0x80000003:
		reg.eax = 0x286C6574; reg.ebx = 0x50202952; reg.ecx = 0x69746E65; reg.edx = 0x52286D75;

		break;
	case 0x80000004:
		reg.eax = 0x20342029; reg.ebx = 0x20555043; reg.ecx = 0x30322E33; reg.edx = 0x007A4847;
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_p4_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 4:
		switch (ecx){
		case 0:
			reg.eax = 0x00004121; reg.ebx = 0x01C0003F; reg.ecx = 0x0000001F; reg.edx = 0x00000000;
			break;
		case 1:
			reg.eax = 0x00004143; reg.ebx = 0x01C0103F; reg.ecx = 0x000007FF; reg.edx = 0x00000000;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef P4D_EMU
void emu_p4d_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x00000006; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;

		break;
	case 1:
		reg.eax = 0x00000F65; reg.ebx = 0x00020800 + (cpunum << 24); reg.ecx = 0x0000E49D; reg.edx = 0xBFEBFBFF;

		break;
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x20202020; reg.ebx = 0x20202020; reg.ecx = 0x20202020; reg.edx = 0x6E492020;

		break;
	case 0x80000003:
		reg.eax = 0x286C6574; reg.ebx = 0x50202952; reg.ecx = 0x69746E65; reg.edx = 0x52286D75;

		break;
	case 0x80000004:
		reg.eax = 0x20442029; reg.ebx = 0x20555043; reg.ecx = 0x30342E33; reg.edx = 0x007A4847;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_p4d_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 4:
		switch (ecx){
		case 0:
			reg.eax = 0x04000121; reg.ebx = 0x01C0003F; reg.ecx = 0x0000001F; reg.edx = 0x00000000;

			break;
		case 1:
			reg.eax = 0x04000143; reg.ebx = 0x01C0103F; reg.ecx = 0x000007FF; reg.edx = 0x00000000;

			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef C2S_EMU
void emu_c2s_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000A; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:
		reg.eax = 0x00010661; reg.ebx = 0x00010800; reg.ecx = 0x0000E31D; reg.edx = 0xAFEBFBFF;
		break;
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x65746E49; reg.ebx = 0x2952286C; reg.ecx = 0x6C654320; reg.edx = 0x6E6F7265;

		break;
	case 0x80000003:
		reg.eax = 0x20295228; reg.ebx = 0x20555043; reg.ecx = 0x20202020; reg.edx = 0x20202020;

		break;
	case 0x80000004:
		reg.eax = 0x30353420; reg.ebx = 0x20402020; reg.ecx = 0x30322E32; reg.edx = 0x007A4847;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_c2s_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 4:
		switch (ecx){
		case 0:
			reg.eax = 0x00000121; reg.ebx = 0x01C0003F; reg.ecx = 0x0000003F; reg.edx = 0x00000001;

			break;
		case 1:
			reg.eax = 0x00000122; reg.ebx = 0x01C0003F; reg.ecx = 0x0000003F; reg.edx = 0x00000001;

			break;
		case 2:
			reg.eax = 0x00000143; reg.ebx = 0x0040003F; reg.ecx = 0x00000FFF; reg.edx = 0x00000001;

			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif


#ifdef C2D_EMU
void emu_c2d_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000A; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:
		reg.eax = 0x000006F6; reg.ebx = 0x00020800 + (cpunum << 24); reg.ecx = 0x0000E3BD; reg.edx = 0xBFEBFBFF;
		break;
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x65746E49; reg.ebx = 0x2952286C; reg.ecx = 0x726F4320; reg.edx = 0x4D542865;

		break;
	case 0x80000003:
		reg.eax = 0x43203229; reg.ebx = 0x20205550; reg.ecx = 0x20202020; reg.edx = 0x20202020;

		break;
	case 0x80000004:
		reg.eax = 0x30323336; reg.ebx = 0x20402020; reg.ecx = 0x36382E31; reg.edx = 0x007A4847;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_c2d_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 4:
		switch (ecx){
		case 0:
			reg.eax = 0x04000121; reg.ebx = 0x01C0003F; reg.ecx = 0x0000003F; reg.edx = 0x00000001;

			break;
		case 1:
			reg.eax = 0x04000122; reg.ebx = 0x01C0003F; reg.ecx = 0x0000003F; reg.edx = 0x00000001;

			break;
		case 2:
			reg.eax = 0x04004143; reg.ebx = 0x03C0003F; reg.ecx = 0x00000FFF; reg.edx = 0x00000001;

			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif


#ifdef C2Q_EMU
void emu_c2q_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000A;
		reg.ebx = 0x756E6547;
		reg.ecx = 0x6C65746E;
		reg.edx = 0x49656E69;
		break;
	case 1:
		reg.eax = 0x00010677;
		reg.ebx = 0x00040800 + (cpunum << 24);
		reg.ecx = 0x0008E39D;
		reg.edx = 0xBFEBFBFF;
		break;
	case 0x80000000:
		reg.eax = 0x80000008;
		reg.ebx = 0x00000000;
		reg.ecx = 0x00000000;
		reg.edx = 0x00000000;
		break;
	case 0x80000002:
		reg.eax = 0x65746E49;
		reg.ebx = 0x2952286C;
		reg.ecx = 0x726F4320;
		reg.edx = 0x4D542865;
		break;
	case 0x80000003:
		reg.eax = 0x51203229;
		reg.ebx = 0x20646175;
		reg.ecx = 0x55504320;
		reg.edx = 0x51202020;
		break;
	case 0x80000004:
		reg.eax = 0x30303238;
		reg.ebx = 0x20402020;
		reg.ecx = 0x33332E32;
		reg.edx = 0x007A4847;
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_c2q_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 4:
		switch (ecx){
		case 0:
			reg.eax = 0x0C000121;
			reg.ebx = 0x01C0003F;
			reg.ecx = 0x0000003F;
			reg.edx = 0x00000001;
			break;
		case 1:
			reg.eax = 0x0C000122;
			reg.ebx = 0x01C0003F;
			reg.ecx = 0x0000003F;
			reg.edx = 0x00000001;
			break;
		case 2:
			reg.eax = 0x0C004143;
			reg.ebx = 0x01C0003F;
			reg.ecx = 0x00000FFF;
			reg.edx = 0x00000001;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef I7_870_EMU
void emu_i7_870_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000B; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:{
		DWORD c = ((cpunum & 0x3) << 1) + ((cpunum >> 2) & 1);
		reg.eax = 0x000106E5; reg.ebx = 0x00100800 + (c << 24); reg.ecx = 0x0098E3FD; reg.edx = 0xBFEBFBFF;
		break;
	}
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x65746E49; reg.ebx = 0x2952286C; reg.ecx = 0x726F4320; reg.edx = 0x4D542865;

		break;
	case 0x80000003:
		reg.eax = 0x37692029; reg.ebx = 0x55504320; reg.ecx = 0x20202020; reg.edx = 0x20202020;

		break;
	case 0x80000004:
		reg.eax = 0x30373820; reg.ebx = 0x20402020; reg.ecx = 0x33392E32; reg.edx = 0x007A4847;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_i7_870_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 11:{
		DWORD c = ((cpunum & 0x3) << 1) + ((cpunum >> 2) & 1);
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + c;
			break;
		case 1:
			reg.eax = 0x00000004; reg.ebx = 0x00000008; reg.ecx = 0x00000201; reg.edx = 0x00000000 + c;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	}
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef I3_2100_EMU
void emu_i3_2100_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000D; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;

		break;
	case 1:{
		DWORD c = ((cpunum & 0x1) << 1) + ((cpunum >> 1) & 1);
		reg.eax = 0x000206A7; reg.ebx = 0x00100800 + (c << 24); reg.ecx = 0x1D9AE3BF; reg.edx = 0xBFEBFBFF;

		break;
	}
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x20202020; reg.ebx = 0x20202020; reg.ecx = 0x65746E49; reg.edx = 0x2952286C;

		break;
	case 0x80000003:
		reg.eax = 0x726F4320; reg.ebx = 0x4D542865; reg.ecx = 0x33692029; reg.edx = 0x3031322D;

		break;
	case 0x80000004:
		reg.eax = 0x50432030; reg.ebx = 0x20402055; reg.ecx = 0x30312E33; reg.edx = 0x007A4847;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_i3_2100_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 11:{
		DWORD c = ((cpunum & 0x1) << 1) + ((cpunum >> 1) & 1);
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + c;
			break;
		case 1:
			reg.eax = 0x00000004; reg.ebx = 0x00000004; reg.ecx = 0x00000201; reg.edx = 0x00000000 + c;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	}
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef I7_2600_EMU
void emu_i7_2600_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000D; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;

		break;
	case 1:{
		DWORD c = ((cpunum & 0x3) << 1) + ((cpunum >> 2) & 1);
		reg.eax = 0x000206A7; reg.ebx = 0x00100800 + (c << 24); reg.ecx = 0x1FBAE3FF; reg.edx = 0xBFEBFBFF;

		break;
	}
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x20202020; reg.ebx = 0x20202020; reg.ecx = 0x65746E49; reg.edx = 0x2952286C;

		break;
	case 0x80000003:
		reg.eax = 0x726F4320; reg.ebx = 0x4D542865; reg.ecx = 0x37692029; reg.edx = 0x3036322D;

		break;
	case 0x80000004:
		reg.eax = 0x50432030; reg.ebx = 0x20402055; reg.ecx = 0x30342E33; reg.edx = 0x007A4847;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_i7_2600_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 11:{
		DWORD c = ((cpunum & 0x3) << 1) + ((cpunum >> 2) & 1);
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + c;
			break;
		case 1:
			reg.eax = 0x00000004; reg.ebx = 0x00000008; reg.ecx = 0x00000201; reg.edx = 0x00000000 + c;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	}
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef I7_3770_EMU
void emu_i7_3770_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000D; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:
		reg.eax = 0x000306A9; reg.ebx = 0x00100800 + (cpunum << 24); reg.ecx = 0x7FBAE3FF; reg.edx = 0xBFEBFBFF;
		break;
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x20202020; reg.ebx = 0x20202020; reg.ecx = 0x65746E49; reg.edx = 0x2952286C;

		break;
	case 0x80000003:
		reg.eax = 0x726F4320; reg.ebx = 0x4D542865; reg.ecx = 0x37692029; reg.edx = 0x3737332D;

		break;
	case 0x80000004:
		reg.eax = 0x50432030; reg.ebx = 0x20402055; reg.ecx = 0x30342E33; reg.edx = 0x007A4847;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_i7_3770_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 11:
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + cpunum;
			break;
		case 1:
			reg.eax = 0x00000004; reg.ebx = 0x00000008; reg.ecx = 0x00000201; reg.edx = 0x00000000 + cpunum;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef I7_4770_EMU
void emu_i7_4770_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 0:
		reg.eax = 0x0000000D; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:
		reg.eax = 0x000306C3; reg.ebx = 0x00100800 + (cpunum << 24); reg.ecx = 0x7FFAFBFF; reg.edx = 0xBFEBFBFF;
		break;
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		reg.eax = 0x65746E49; reg.ebx = 0x2952286C; reg.ecx = 0x726F4320; reg.edx = 0x4D542865;

		break;
	case 0x80000003:
		reg.eax = 0x37692029; reg.ebx = 0x3737342D; reg.ecx = 0x50432030; reg.edx = 0x20402055;

		break;
	case 0x80000004:
		reg.eax = 0x30342E33; reg.ebx = 0x007A4847; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_i7_4770_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 11:
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + cpunum;
			break;
		case 1:
			reg.eax = 0x00000004; reg.ebx = 0x00000008; reg.ecx = 0x00000201; reg.edx = 0x00000000 + cpunum;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef E5_2608V3D_EMU
void emu_e5_2608v3d_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;
	char cpuname[16 * 3];
	ZeroMemory(cpuname, sizeof(cpuname));
	// 01234567890ABCDEF
	//         01234567890ABCDEF
	// Intel Xeon E5-2608 v3 @ 2.0GHz
	strcpy_s(cpuname, sizeof(cpuname), "Intel Xeon E5-2608 v3 @ 2.0GHz");
	switch (eax){
	case 0:
		reg.eax = 0x0000000D; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:{
		DWORD c = ((cpunum / 12) << 4) + (cpunum % 12);
		reg.eax = 0x000306C3; reg.ebx = 0x00100800 + (c << 24); reg.ecx = 0x7FFAFBFF; reg.edx = 0xBFEBFBFF;
		break;
	}
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;

	case 0x80000002:
		memcpy(reg.vec, cpuname, 16);
		break;
	case 0x80000003:
		memcpy(reg.vec, cpuname + 16, 16);
		break;
	case 0x80000004:
		memcpy(reg.vec, cpuname + 32, 16);
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
void emu_e5_2608v3d_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;
	DWORD c = ((cpunum / 12) << 4) + (cpunum % 12);

	switch (eax){
	case 11:
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + c;
			break;
		case 1:
			reg.eax = 0x00000004; reg.ebx = 0x00000008; reg.ecx = 0x00000201; reg.edx = 0x00000000 + c;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef E5_2698V3D_EMU
void emu_e5_2698v3d_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;
	char cpuname[16 * 3];
	ZeroMemory(cpuname, sizeof(cpuname));
	// 01234567890ABCDEF
	//         01234567890ABCDEF
	// Intel Xeon E5-2698 v3 @ 2.3GHz
	strcpy_s(cpuname, sizeof(cpuname), "Intel Xeon E5-2698 v3 @ 2.3GHz");
	switch (eax){
	case 0:
		reg.eax = 0x0000000D; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:
		reg.eax = 0x000306C3; reg.ebx = 0x00100800 + (cpunum << 24); reg.ecx = 0x7FFAFBFF; reg.edx = 0xBFEBFBFF;
		break;
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;

	case 0x80000002:
		memcpy(reg.vec, cpuname, 16);
		break;
	case 0x80000003:
		memcpy(reg.vec, cpuname + 16, 16);
		break;
	case 0x80000004:
		memcpy(reg.vec, cpuname + 32, 16);
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
void emu_e5_2698v3d_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;

	switch (eax){
	case 11:
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + cpunum;
			break;
		case 1:
			reg.eax = 0x00000005; reg.ebx = 0x00000008; reg.ecx = 0x00000201; reg.edx = 0x00000000 + cpunum;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif

#ifdef E7_4809V2Q_EMU
void emu_e7_4809v2q_cpuid(int* regout, int eax){
	REG32& reg = *(REG32*)regout;
	char cpuname[16 * 3];
	ZeroMemory(cpuname, sizeof(cpuname));
	// 01234567890ABCDEF
	//         01234567890ABCDEF
	// Intel Xeon E5-2698 v3 @ 2.3GHz
	strcpy_s(cpuname, sizeof(cpuname), "Intel Xeon E7-4809 v2 @ 1.9GHz");

	switch (eax){
	case 0:
		reg.eax = 0x0000000D; reg.ebx = 0x756E6547; reg.ecx = 0x6C65746E; reg.edx = 0x49656E69;
		break;
	case 1:{
		DWORD c = ((cpunum / 12) << 4) + (cpunum % 12);
		reg.eax = 0x000306A9; reg.ebx = 0x00100800 + (c << 24); reg.ecx = 0x7FBAE3FF; reg.edx = 0xBFEBFBFF;
		break;
	}
	case 0x80000000:
		reg.eax = 0x80000008; reg.ebx = 0x00000000; reg.ecx = 0x00000000; reg.edx = 0x00000000;

		break;
	case 0x80000002:
		memcpy(reg.vec, cpuname, 16);
		break;
	case 0x80000003:
		memcpy(reg.vec, cpuname + 16, 16);
		break;
	case 0x80000004:
		memcpy(reg.vec, cpuname + 32, 16);
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}

void emu_e7_4809v2q_cpuidex(int* regout, int eax, int ecx){
	REG32& reg = *(REG32*)regout;
	DWORD c = ((cpunum / 12) << 4) + (cpunum % 12);

	switch (eax){
	case 11:
		switch (ecx){
		case 0:
			reg.eax = 0x00000001; reg.ebx = 0x00000002; reg.ecx = 0x00000100; reg.edx = 0x00000000 + c;
			break;
		case 1:
			reg.eax = 0x00000004; reg.ebx = 0x00000008; reg.ecx = 0x00000201; reg.edx = 0x00000000 + c;
			break;
		default:
			MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
			break;
		}
		break;
	default:
		MessageBox(0, _TEXT("サポートされていません"), _TEXT("error"), MB_OK);
		break;
	}
}
#endif


cpuemu.h

#ifndef CPU_EMU_H

#define CPU_EMU_H 0x01


//#define P4_EMU 1	//	Pentium 4 641をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define P4D_EMU 1	//	PentiumD 945をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define C2S_EMU 1	//	Celeron 450をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define C2D_EMU 1	//	Core2Duo E6320をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define C2Q_EMU 1	//	Core2Quad Q8200をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define I7_870_EMU 1	//	Core i7 870をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define I3_2100_EMU 1	//	Core i3 2100をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define I7_2600_EMU 1	//	Core i7 2600をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define I7_3770_EMU 1	//	Core i7 3770をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define I7_4770_EMU 1	//	Core i7 4770をエミュレーションする場合(実機からCPUIDを抽出して作成)
//#define E5_2608V3D_EMU 1	//	Xeon E5-2608v3*2をエミュレーションする場合(推定)
//#define E5_2698V3D_EMU 1	//	Xeon E5-2698v3*2をエミュレーションする場合(推定)
//#define E7_4809V2Q_EMU 1	//	Xeon E7-4809v2*4をエミュレーションする場合(推定)


#ifdef P4_EMU
#define __cpuid(reg,eax)  emu_p4_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_p4_cpuidex(reg,eax,ecx)
#define CPU_EMU 2
#endif

#ifdef P4D_EMU
#define __cpuid(reg,eax)  emu_p4d_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_p4d_cpuidex(reg,eax,ecx) 
#define CPU_EMU 2
#endif

#ifdef C2S_EMU
#define __cpuid(reg,eax)  emu_c2s_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_c2s_cpuidex(reg,eax,ecx) 
#define CPU_EMU 1
#endif


#ifdef C2D_EMU
#define __cpuid(reg,eax)  emu_c2d_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_c2d_cpuidex(reg,eax,ecx) 
#define CPU_EMU 2
#endif

#ifdef C2Q_EMU
#define __cpuid(reg,eax)  emu_c2q_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_c2q_cpuidex(reg,eax,ecx) 
#define CPU_EMU 4
#endif

#ifdef I7_870_EMU
#define __cpuid(reg,eax)  emu_i7_870_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_i7_870_cpuidex(reg,eax,ecx) 
#define CPU_EMU 8
#endif

#ifdef I3_2100_EMU
#define __cpuid(reg,eax)  emu_i3_2100_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_i3_2100_cpuidex(reg,eax,ecx) 
#define CPU_EMU 4
#endif


#ifdef I7_2600_EMU
#define __cpuid(reg,eax)  emu_i7_2600_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_i7_2600_cpuidex(reg,eax,ecx) 
#define CPU_EMU 8
#endif

#ifdef I7_3770_EMU
#define __cpuid(reg,eax)  emu_i7_3770_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_i7_3770_cpuidex(reg,eax,ecx) 
#define CPU_EMU 8
#endif


#ifdef I7_4770_EMU
#define __cpuid(reg,eax)  emu_i7_4770_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_i7_4770_cpuidex(reg,eax,ecx) 
#define CPU_EMU 8
#endif

#ifdef E5_2608V3D_EMU
#define __cpuid(reg,eax)  emu_e5_2608v3d_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_e5_2608v3d_cpuidex(reg,eax,ecx) 
#define CPU_EMU (12*2)
#endif

#ifdef E5_2698V3D_EMU
#define __cpuid(reg,eax)  emu_e5_2698v3d_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_e5_2698v3d_cpuidex(reg,eax,ecx) 
#define CPU_EMU (32*2)
#endif

#ifdef E7_4809V2Q_EMU
#define __cpuid(reg,eax)  emu_e7_4809v2q_cpuid(reg,eax) 
#define __cpuidex(reg,eax,ecx)  emu_e7_4809v2q_cpuidex(reg,eax,ecx) 
#define CPU_EMU (12*4)
#endif

#ifndef CPU_CPP
	#ifdef CPU_EMU
		DWORD cpunum = 0;	//	エミュレーションするCPU番号
	#endif
#else
#ifdef CPU_EMU
	extern DWORD cpunum;	//	エミュレーションするCPU番号
#endif

#endif

	void emu_p4_cpuid(int* regout, int eax);
	void emu_p4_cpuidex(int* regout, int eax, int ecx);
	void emu_p4d_cpuid(int* regout, int eax);
	void emu_p4d_cpuidex(int* regout, int eax, int ecx);
	void emu_c2s_cpuid(int* regout, int eax);
	void emu_c2s_cpuidex(int* regout, int eax, int ecx);
	void emu_c2d_cpuid(int* regout, int eax);
	void emu_c2d_cpuidex(int* regout, int eax, int ecx);
	void emu_c2q_cpuid(int* regout, int eax);
	void emu_c2q_cpuidex(int* regout, int eax, int ecx);
	void emu_i7_870_cpuid(int* regout, int eax);
	void emu_i7_870_cpuidex(int* regout, int eax, int ecx);
	void emu_i3_2100_cpuid(int* regout, int eax);
	void emu_i3_2100_cpuidex(int* regout, int eax, int ecx);
	void emu_i7_2600_cpuid(int* regout, int eax);
	void emu_i7_2600_cpuidex(int* regout, int eax, int ecx);
	void emu_i7_3770_cpuid(int* regout, int eax);
	void emu_i7_3770_cpuidex(int* regout, int eax, int ecx);
	void emu_i7_4770_cpuid(int* regout, int eax);
	void emu_i7_4770_cpuidex(int* regout, int eax, int ecx);
	void emu_e5_2608v3d_cpuid(int* regout, int eax);
	void emu_e5_2608v3d_cpuidex(int* regout, int eax, int ecx);
	void emu_e5_2698v3d_cpuid(int* regout, int eax);
	void emu_e5_2698v3d_cpuidex(int* regout, int eax, int ecx);
	void emu_e7_4809v2q_cpuid(int* regout, int eax);
	void emu_e7_4809v2q_cpuidex(int* regout, int eax, int ecx);


#endif

resource.h

#define IDC_LISTVIEW100	110

resource.rc

#include <windows.h>
#include	"resource.h"


DLG1 DIALOG DISCARDABLE 0, 0, 400, 240
EXSTYLE WS_EX_DLGMODALFRAME
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | DS_SETFONT
CAPTION "CPUID3"
FONT 9, "MS 明朝"
{

CONTROL "ListView100", IDC_LISTVIEW100, "SYSLISTVIEW32", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT, 7, 7, 384, 200

 CONTROL "OK", IDOK, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 173, 214, 54, 12
}

実行ファイルとソースファイルのダウンロード