CPUの物理CPU数・ソケット数等を取得(32/64bit)

icon 項目のみ表示/展開表示の切り替え

概要

現在の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
}

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