C++とアセンブラーでCPU機能を読み出す

CPUの機能を読み出し、それを表示してみましょう。
arques.hatenablog.com
のアゼンブラーバージョンです。

C++ソースリスト

#include <iostream>
#include <bitset>

using namespace std;

extern "C" void myCpuid(int*, int); // assembler function

using namespace std;

enum _ECX       // CpuId(1, 0)
{
    SSE3 = 0,
    PCLMULQDQ = 1,
    DTES64 = 2,
    MONITOR = 3,
    DS_CPL = 4,
    VMX = 5,
    SMX = 6,
    EST = 7,
    TM2 = 8,
    SSSE3 = 9,
    CNXT_ID = 10,
    SDBG = 11,
    FMA = 12,
    CX16 = 13,
    XTPR = 14,
    PDCM = 15,
    PCID = 17,
    DCA = 18,
    SSE41 = 19,
    SSE42 = 20,
    X2APIC = 21,
    MOVBE = 22,
    POPCNT = 23,
    TSC_DEADLINE = 24,
    AES = 25,
    XSAVE = 26,
    OSXSAVE = 27,
    AVX = 28,
    F16C = 29,
    RDRND = 30,
    HYPERVISOR = 31
};

enum _EDX       // CpuId(1, 0)
{
    FPU = 0,
    VME = 1,
    DE = 2,
    PSE = 3,
    TSC = 4,
    MSR = 5,
    PAE = 6,
    MCE = 7,
    CX8 = 8,
    APIC = 9,
    SEP = 11,
    MTRR = 12,
    PGE = 13,
    MCA = 14,
    CMOV = 15,
    PAT = 16,
    PSE_36 = 17,
    PSN = 18,
    CLFSH = 19,
    DS = 21,
    ACPI = 22,
    MMX = 23,
    FXSR = 24,
    SSE = 25,
    SSE2 = 26,
    SS = 27,
    HTT = 28,
    TM = 29,
    IA64 = 30,
    PBE = 31
};

enum _EBX       // CpuId(7, 0)
{
    AVX2 = 5,
    AVX512F = 16
};

void dipsFeatures(string isa_feature, bitset<32> _REG_, int pos)
{
    cout << isa_feature << (_REG_[pos] ?
        " supported." : " not supported!") << std::endl;
}


int main()
{
    int regs[4];

    myCpuid(regs, 0);
    int nMax = regs[0];
    if (nMax >= 1)
    {
        myCpuid(regs, 1);
        bitset<32> _EDX_(regs[3]);
        cout << hex << _EDX_ << endl;
        dipsFeatures("FPU          ", _EDX_, _EDX::FPU);
        dipsFeatures("VME          ", _EDX_, _EDX::VME);
        dipsFeatures("DE           ", _EDX_, _EDX::DE);
        dipsFeatures("PSE          ", _EDX_, _EDX::PSE);
        dipsFeatures("TSC          ", _EDX_, _EDX::TSC);
        dipsFeatures("MSR          ", _EDX_, _EDX::MSR);
        dipsFeatures("PAE          ", _EDX_, _EDX::PAE);
        dipsFeatures("MCE          ", _EDX_, _EDX::MCE);
        dipsFeatures("CX8          ", _EDX_, _EDX::CX8);
        dipsFeatures("APIC         ", _EDX_, _EDX::APIC);
        dipsFeatures("SEP          ", _EDX_, _EDX::SEP);
        dipsFeatures("MTRR         ", _EDX_, _EDX::MTRR);
        dipsFeatures("PGE          ", _EDX_, _EDX::PGE);
        dipsFeatures("MCA          ", _EDX_, _EDX::MCA);
        dipsFeatures("CMOV         ", _EDX_, _EDX::CMOV);
        dipsFeatures("PAT          ", _EDX_, _EDX::PAT);
        dipsFeatures("PSE-36       ", _EDX_, _EDX::PSE_36);
        dipsFeatures("PSN          ", _EDX_, _EDX::PSN);
        dipsFeatures("CLFSH        ", _EDX_, _EDX::CLFSH);
        dipsFeatures("DS           ", _EDX_, _EDX::DS);
        dipsFeatures("ACPI         ", _EDX_, _EDX::ACPI);
        dipsFeatures("MMX          ", _EDX_, _EDX::MMX);
        dipsFeatures("FXSR         ", _EDX_, _EDX::FXSR);
        dipsFeatures("SSE          ", _EDX_, _EDX::SSE);
        dipsFeatures("SSE2         ", _EDX_, _EDX::SSE2);
        dipsFeatures("SS           ", _EDX_, _EDX::SS);
        dipsFeatures("HTT          ", _EDX_, _EDX::HTT);
        dipsFeatures("TM           ", _EDX_, _EDX::TM);
        dipsFeatures("IA64         ", _EDX_, _EDX::IA64);
        dipsFeatures("PBE          ", _EDX_, _EDX::PBE);

        bitset<32> _ECX_(regs[2]);
        dipsFeatures("SSE3         ", _ECX_, _ECX::SSE3);
        dipsFeatures("PCLMULQDQ    ", _ECX_, _ECX::PCLMULQDQ);
        dipsFeatures("DTES64       ", _ECX_, _ECX::DTES64);
        dipsFeatures("MONITOR      ", _ECX_, _ECX::MONITOR);
        dipsFeatures("DS_CPL       ", _ECX_, _ECX::DS_CPL);
        dipsFeatures("VMX          ", _ECX_, _ECX::VMX);
        dipsFeatures("SMX          ", _ECX_, _ECX::SMX);
        dipsFeatures("EST          ", _ECX_, _ECX::EST);
        dipsFeatures("TM2          ", _ECX_, _ECX::TM2);
        dipsFeatures("SSSE3        ", _ECX_, _ECX::SSSE3);
        dipsFeatures("CNXT_ID      ", _ECX_, _ECX::CNXT_ID);
        dipsFeatures("SDBG         ", _ECX_, _ECX::SDBG);
        dipsFeatures("FMA          ", _ECX_, _ECX::FMA);
        dipsFeatures("CX16         ", _ECX_, _ECX::CX16);
        dipsFeatures("XTPR         ", _ECX_, _ECX::XTPR);
        dipsFeatures("PDCM         ", _ECX_, _ECX::PDCM);
        dipsFeatures("PCID         ", _ECX_, _ECX::PCID);
        dipsFeatures("DCA          ", _ECX_, _ECX::DCA);
        dipsFeatures("SSE41        ", _ECX_, _ECX::SSE41);
        dipsFeatures("SSE42        ", _ECX_, _ECX::SSE42);
        dipsFeatures("X2APIC       ", _ECX_, _ECX::X2APIC);
        dipsFeatures("MOVBE        ", _ECX_, _ECX::MOVBE);
        dipsFeatures("POPCNT       ", _ECX_, _ECX::POPCNT);
        dipsFeatures("TSC_DEADLINE ", _ECX_, _ECX::TSC_DEADLINE);
        dipsFeatures("AES          ", _ECX_, _ECX::AES);
        dipsFeatures("XSAVE        ", _ECX_, _ECX::XSAVE);
        dipsFeatures("OSXSAVE      ", _ECX_, _ECX::OSXSAVE);
        dipsFeatures("AVX          ", _ECX_, _ECX::AVX);
        dipsFeatures("F16C         ", _ECX_, _ECX::F16C);
        dipsFeatures("RDRND        ", _ECX_, _ECX::RDRND);
        dipsFeatures("HYPERVISOR   ", _ECX_, _ECX::HYPERVISOR);
    }
    if (nMax >= 7)
    {
        myCpuid(regs, 7);
        bitset<32> _EBX_(regs[1]);
        dipsFeatures("AVX2         ", _EBX_, _EBX::AVX2);
        dipsFeatures("AVX512F      ", _EBX_, _EBX::AVX512F);
    }
}

アセンブリ関数ソースリスト

__cpuidイントリンシックを、アセンブリ言語の関数で実装します。関数名はmyCpuidです。基本的にmyCpuidは__cpuidイントリンシックと互換があります。

include ksamd64.inc

_TEXT       segment

;
; rcx = stringの先頭アドレス。
; rdx = function #
;
        public  myCpuid
        align   16

myCpuid proc    frame           ; prologを使う時はproc frame
        ; prolog
        rex_push_reg    rbx     ; マクロでrbxをpush
        .endprolog              ; end of prolog

        mov     r9, rcx         ; addr

        mov     eax, edx
        xor     ecx, ecx
        cpuid
        mov     [r9+0],  eax
        mov     [r9+4],  ebx
        mov     [r9+8],  ecx
        mov     [r9+12], edx

        ; epilog
        pop     rbx             ; restore
        ret

myCpuid endp

_TEXT   ends
        end

CPU brand string: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHzで実行した例:

FPU           supported.
VME           supported.
DE            supported.
PSE           supported.
TSC           supported.
MSR           supported.
PAE           supported.
MCE           supported.
CX8           supported.
APIC          supported.
SEP           supported.
MTRR          supported.
PGE           supported.
MCA           supported.
CMOV          supported.
PAT           supported.
PSE-36        supported.
PSN           not supported!
CLFSH         supported.
DS            supported.
ACPI          supported.
MMX           supported.
FXSR          supported.
SSE           supported.
SSE2          supported.
SS            supported.
HTT           supported.
TM            supported.
IA64          not supported!
PBE           supported.
SSE3          supported.
PCLMULQDQ     supported.
DTES64        supported.
MONITOR       supported.
DS_CPL        supported.
VMX           supported.
SMX           not supported!
EST           supported.
TM2           supported.
SSSE3         supported.
CNXT_ID       not supported!
SDBG          supported.
FMA           supported.
CX16          supported.
XTPR          supported.
PDCM          supported.
PCID          supported.
DCA           not supported!
SSE41         supported.
SSE42         supported.
X2APIC        supported.
MOVBE         supported.
POPCNT        supported.
TSC_DEADLINE  supported.
AES           supported.
XSAVE         supported.
OSXSAVE       supported.
AVX           supported.
F16C          supported.
RDRND         supported.
HYPERVISOR    not supported!
AVX2          supported.
AVX512F       supported.