山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他CPUの物理CPU数・ソケット数等を取得(32/64bit)
概要
現在の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つのスレッドを割り付けないようにするためには、この違いを検出して対処する必要がある。
例えばハイパースレッドをサポートしている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*)®
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
}
Copyright (C) 2012 山本ワールド All Rights Reserved.