Tested on Win 10.
Code: Select all
DeclareModule CPUID
Declare.i IsSupported () ; Check if CPUID is supported by the CPU
Declare CPUID (leaf.l, *eax, *ebx, *ecx, *edx) ; This wraps the CPUID instruction.
Declare GetHighestLeaf (Extended.l, *HighestLeaf, *Manufacturer = #Null) ; Get the 'highest' or 'highest extended' leaf level supported by CPUID and optionally the manufacturer ID.
EndDeclareModule
Module CPUID
EnableExplicit
Procedure.i IsSupported ()
;> Check if CPUID is supported by the CPU
; It was introduced in 1993 at the time of the Pentium, so ... but you may do a check before calling the other functions.
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x64)
ProcedureReturn 1 ; CPUID is always present on 64 bit CPUs
CompilerEndIf
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
!pushfd
!pop eax
!mov edx, eax
!xor eax, 0x00200000
!push eax
!popfd
!pushfd
!pop eax
!xor eax, edx
!jne IsCpuid_OK
!xor eax, eax
!ret
!IsCpuid_OK:
!mov eax, 1
!ret
CompilerEndIf
CompilerIf #PB_Compiler_Backend = #PB_Backend_C
!asm volatile (".intel_syntax noprefix;"
!"pushfd;"
!"pop eax;"
!"mov edx, eax;"
!"xor eax, 0x00200000;"
!"push eax;"
!"popfd;"
!"pushfd;"
!"pop eax;"
!"xor eax, edx;"
!"jne IsCpuid_OK;"
!"mov %[retval], 0;"
!"jmp IsCpuid_EXIT;"
!"IsCpuid_OK:"
!"mov %[retval], 1;"
!"IsCpuid_EXIT:"
!".att_syntax;"
!: [retval] "=r" (r)
!);
!return r;
CompilerEndIf
CompilerEndIf
EndProcedure
Procedure GetHighestLeaf (Extended.l, *HighestLeaf, *Manufacturer = #Null)
;> Get the 'highest' or 'highest extended' leaf level supported by CPUID and optionally the manufacturer ID.
; If Extended is = 0 the long pointed by *HighestLeaf will contain the highest leaf level supported.
; If Extended is = $80000000 the long pointed by *HighestLeaf will contain the highest extended leaf level supported.
; *HighestLeaf must be a pointer to a 32 bit integer (PB long)
; If *Manufacturer is not null it must point to a string of at least 12 * SizeOf(Character) + null termination.
; It will contain the manufacturer string ID of the CPU (AuthenticAMD, Genuineintel, etc.)
; Before calling CPUID() you should verify if the leaf level you are going to request is supported using this function.
Protected.l mf1, mf2, mf3
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
!mov eax, dword [p.v_Extended]
!CPUID
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
!mov ebp, dword [p.p_HighestLeaf]
!mov dword [ebp], eax
CompilerElse
!mov rbp, qword [p.p_HighestLeaf]
!mov dword [rbp], eax
CompilerEndIf
!mov dword [p.v_mf1], ebx
!mov dword [p.v_mf2], edx
!mov dword [p.v_mf3], ecx
CompilerEndIf
CompilerIf #PB_Compiler_Backend = #PB_Backend_C
!unsigned int reg_a, reg_b, reg_c, reg_d;
!asm volatile ("cpuid;"
!: "=a" (reg_a), "=b" (reg_b), "=c" (reg_c), "=d" (reg_d)
!: "0" (v_extended)
!);
! * (unsigned int *) p_highestleaf = reg_a;
! v_mf1 = reg_b;
! v_mf2 = reg_d;
! v_mf3 = reg_c;
CompilerEndIf
If *Manufacturer
PokeS(*Manufacturer, PeekS(@mf1, 4, #PB_Ascii) + PeekS(@mf2, 4, #PB_Ascii) + PeekS(@mf3, 4, #PB_Ascii))
EndIf
EndProcedure
Procedure CPUID (leaf.l, *eax, *ebx, *ecx, *edx)
;> This wraps the CPUID instruction.
; leaf must be a 32 bit integer (PB long)
; It must contain the numerical id of the requested level of information and it will be loaded in the EAX register.
; *eax, *ebx, *ecx, *edx must be pointers to 32 bit integers (PB long)
; They will contain a copy of the values stored in the cpu registers after CPUID has been called.
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
!mov eax, dword [p.v_leaf]
!CPUID
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
!mov ebp, dword [p.p_eax]
!mov dword [ebp], eax
!mov ebp, dword [p.p_ebx]
!mov dword [ebp], ebx
!mov ebp, dword [p.p_ecx]
!mov dword [ebp], ecx
!mov ebp, dword [p.p_edx]
!mov dword [ebp], edx
CompilerElse
!mov rbp, qword [p.p_eax]
!mov dword [rbp], eax
!mov rbp, qword [p.p_ebx]
!mov dword [rbp], ebx
!mov rbp, qword [p.p_ecx]
!mov dword [rbp], ecx
!mov rbp, qword [p.p_edx]
!mov dword [rbp], edx
CompilerEndIf
CompilerEndIf
CompilerIf #PB_Compiler_Backend = #PB_Backend_C
!unsigned int reg_a, reg_b, reg_c, reg_d;
!asm volatile ("cpuid;"
!: "=a" (reg_a), "=b" (reg_b), "=c" (reg_c), "=d" (reg_d)
!: "0" (v_leaf)
!);
! * (unsigned int *) p_eax = reg_a;
! * (unsigned int *) p_ebx = reg_b;
! * (unsigned int *) p_ecx = reg_c;
! * (unsigned int *) p_edx = reg_d;
CompilerEndIf
EndProcedure
EndModule
Code: Select all
EnableExplicit
Define text$, backend$, leaf
Define.l eax, ebx, ecx, edx, Highest, HighestExt
Define Manufacturer$ = Space(12)
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
backend$ = "ASM"
CompilerEndIf
CompilerIf #PB_Compiler_Backend = #PB_Backend_C
backend$ = "C"
CompilerEndIf
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
backend$ + " x86"
CompilerElse
backend$ + " x64"
CompilerEndIf
backend$ + " " + #PB_Compiler_Version
text$ = "Backend : " + backend$
If CPUID::IsSupported()
text$ + #CRLF$ + "CPUID is supported."
CPUID::GetHighestLeaf (0, @Highest, @Manufacturer$)
text$ + #CRLF$ + "Manufacturer ID : " + Manufacturer$
text$ + #CRLF$ + "Highest leaf : " + Highest
CPUID::GetHighestLeaf ($80000000, @HighestExt)
text$ + #CRLF$ + "Highest extended leaf : " + "0x" + Hex(HighestExt, #PB_Long)
If ($80000004 & $7FFFFFFF) <= (HighestExt & $7FFFFFFF) ; checks if the required leaves are supported
text$ + #CRLF$ + "Processor string : ["
For leaf = $80000002 To $80000004
CPUID::CPUID (leaf, @eax, @ebx, @ecx, @edx)
text$ + PeekS(@eax, 4, #PB_Ascii) + PeekS(@ebx, 4, #PB_Ascii) + PeekS(@ecx, 4, #PB_Ascii) + PeekS(@edx, 4, #PB_Ascii)
Next
text$ + "]"
Else
text$ + #CRLF$ + "The extended leaves $80000002 - $80000004 are not supported."
EndIf
Else
text$ = "CPUID is not supported."
EndIf
MessageRequester("CPUID", text$)
Code: Select all
Backend : C x86 601
CPUID is supported.
Manufacturer ID : AuthenticAMD
Highest leaf : 13
Highest extended leaf : 0x8000001E
Processor string : [AMD Ryzen 5 3600 6-Core Processor ]