News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

CPU Identification Procedure

Started by MichaelW, June 11, 2005, 07:06:00 PM

Previous topic - Next topic

MichaelW

This is a test version of a CPU identification procedure. The output is limited to 3 lines because it's intended for use with the code timing macros. I'm not sure about some of the details, and I currently have only a P3 model 7 and a K5 model 1 to test it on. I would appreciate it if those of you with other processors would run the attached app and post the results, along with corrections for any incorrect results.

EDIT: Updated to a new version.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
    .586
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    ; -------------------------------------------
    ; Returns a bit range value, with the value
    ; shifted to place lowbit at bit position 0.
    ; -------------------------------------------
    brval MACRO dwordval, highbit, lowbit
        mov   eax, dwordval
        shl   eax, 31-highbit
        shr   eax, 31-highbit+lowbit
        EXITM <eax>
    ENDM

    ; --------------------------------------------
    ; This will overwrite EAX, EBX, ECX, and EDX.
    ; --------------------------------------------
    _cpuid MACRO function
        mov   eax, function
        cpuid
    ENDM

    ; --------------------------------------
    ; Returns 1 if the specified feature is
    ; supported, otherwise 0.
    ; --------------------------------------
    cpufeat MACRO feature:REQ
        push  ebx
        IFIDNI <feature>, <CPUID>
            ;; ---------------------------------
            ;; CPUID supported if can set/clear
            ;; ID flag (EFLAGS bit 21).
            ;; ---------------------------------
            pushfd
            pop   edx
            pushfd
            pop   eax
            xor   eax, 200000h  ; flip ID flag
            push  eax
            popfd
            pushfd
            pop   eax
            xor   eax, edx
        ELSEIFIDNI <feature>, <FPU>
            _cpuid 1
            mov   eax, brval(edx,0,0)
        ELSEIFIDNI <feature>, <TSC>
            _cpuid 1
            mov   eax, brval(edx,4,4)
        ELSEIFIDNI <feature>, <CX8>
            _cpuid 1
            mov   eax, brval(edx,8,8)
        ELSEIFIDNI <feature>, <CMOV>
            _cpuid 1
            mov   eax, brval(edx,15,15)
        ELSEIFIDNI <feature>, <CLFSH>
            _cpuid 1
            mov   eax, brval(edx,19,19)
        ELSEIFIDNI <feature>, <MMX>
            _cpuid 1
            mov   eax, brval(edx,23,23)
        ELSEIFIDNI <feature>, <FXSR>
            _cpuid 1
            mov   eax, brval(edx,24,24)
        ELSEIFIDNI <feature>, <SSE>
            _cpuid 1
            mov   eax, brval(edx,25,25)
        ELSEIFIDNI <feature>, <SSE2>
            _cpuid 1
            mov   eax, brval(edx,26,26)
        ELSEIFIDNI <feature>, <HTT>
            _cpuid 1
            mov   eax, brval(edx,28,28)
        ELSEIFIDNI <feature>, <SSE3>
            _cpuid 1
            mov   eax, brval(ecx,0,0)
        ENDIF       
        pop   ebx
        EXITM <eax>
    ENDM

    VENDOR_OTHER  EQU 0
    VENDOR_INTEL  EQU 1
    VENDOR_AMD    EQU 2

    SWITCH$ EQU <switch$>
    CASE$   EQU <case$>
    ELSE$   EQU <else$>
    ENDSW$  EQU <endsw$>

    NL EQU <13,10>

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    call  IdentifyCPU
    mov   eax, input(NL,"Press enter to exit...")
    exit   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
IdentifyCPU proc uses ebx esi
    LOCAL maxCpuidInput   :DWORD  ; maximum basic function
    LOCAL signature       :DWORD  ; EAX (function 1)
    LOCAL steppingID      :DWORD  ; EAX bits 3-0 (function 1)
    LOCAL model           :DWORD  ; EAX bits 7-4 (function 1)
    LOCAL displayModel    :DWORD  ; calculated
    LOCAL family          :DWORD  ; EAX bits 11-8 (function 1)
    LOCAL displayFamily   :DWORD  ; calculated
    LOCAL extendedModel   :DWORD  ; EAX bits 19-16 (function 1)
    LOCAL extendedFamily  :DWORD  ; EAX bits 27-20 (function 1)
    LOCAL brandID         :DWORD  ; EBX bits 7-0 (function 1)

    LOCAL maxCpuidInputEx :DWORD  ; maximum extended function
    LOCAL signatureEx     :DWORD  ; EAX (function 80000001h)

    LOCAL vendor          :DWORD  ; vendor identifier
    LOCAL vendorID[13]    :BYTE   ; (function 0)

    LOCAL nameString[48]  :BYTE   ; (function 80000002h-4h, AMD)

    mov   vendorID[12],   0       ; as a precaution
    mov   nameString[47], 0       ; as a precaution

    .IF cpufeat(CPUID) == 0
        print chr$("CPUID not supported"),NL
        jmp   fini
    .ENDIF

    _cpuid 0
    mov   maxCpuidInput,          eax
    mov   DWORD PTR vendorID,     ebx
    mov   DWORD PTR vendorID[4],  edx
    mov   DWORD PTR vendorID[8],  ecx

    SWITCH$ ADDR vendorID   
      CASE$ "GenuineIntel"
          mov   vendor, VENDOR_INTEL
      CASE$ "AuthenticAMD"
          mov   vendor, VENDOR_AMD
      ELSE$
          mov   vendor, VENDOR_OTHER
    ENDSW$

    .IF maxCpuidInput > 0
        _cpuid 1
        mov   esi, eax
        mov   signature,      esi
        mov   steppingID,     brval(esi,3,0)
        mov   model,          brval(esi,7,4)
        mov   family,         brval(esi,11,8)
        mov   extendedModel,  brval(esi,19,16)
        mov   extendedFamily, brval(esi,27,20)
        mov   brandID,        brval(ebx,7,0)

        ; -----------------------------------------------
        ; For AMD only use the family and extendedFamily
        ; returned by function 80000001h, if available.
        ; -----------------------------------------------
        .IF vendor == VENDOR_AMD
            _cpuid 80000000h
            .IF eax > 80000000h
                _cpuid 80000001h
                mov   esi, eax
                mov   family,         brval(esi,11,8)
                mov   extendedFamily, brval(esi,27,20)
            .ENDIF
        .ENDIF
    .ENDIF

    ; -------------------------------------------------------
    ; The AMD Processor Name String, supported starting with
    ; the K5 Model 1, contains the actual processor name.
    ; The Intel Processor Brand String is retrieved in the
    ; same manner as the AMD Processor Name String, but
    ; instead of a processor name it contains frequency and
    ; multiplier information that is of no use here.
    ; -------------------------------------------------------
    .IF vendor == VENDOR_AMD
        _cpuid 80000000h
        mov   maxCpuidInputEx, eax
        .IF eax > 80000000h
            _cpuid 80000001h
            mov   signatureEx, eax
            .IF maxCpuidInputEx >= 80000004h
                _cpuid 80000002h
                mov   DWORD PTR nameString,     eax
                mov   DWORD PTR nameString[4],  ebx
                mov   DWORD PTR nameString[8],  ecx
                mov   DWORD PTR nameString[12], edx
                _cpuid 80000003h
                mov   DWORD PTR nameString[16], eax
                mov   DWORD PTR nameString[20], ebx
                mov   DWORD PTR nameString[24], ecx
                mov   DWORD PTR nameString[28], edx
                _cpuid 80000004h
                mov   DWORD PTR nameString[32], eax
                mov   DWORD PTR nameString[36], ebx
                mov   DWORD PTR nameString[40], ecx
                mov   DWORD PTR nameString[44], edx
            .ENDIF
        .ENDIF
    .ENDIF

    ; ------------------------------------------------------------
    ; Use the Intel rules to calc the displayed family and model.
    ; ------------------------------------------------------------
    m2m   displayFamily, family
    m2m   displayModel, model
    .IF family == 0Fh
        mov   eax, extendedFamily
        add   displayFamily, eax
    .ENDIF
    .IF family == 6 || family == 0Fh
        mov   eax, extendedModel
        add   displayModel, eax
    .ENDIF

    ; -----------------------------------------------------------
    ; Display the family, model, and stepping in decimal instead
    ; of the hex that Intel now recommends.
    ; -----------------------------------------------------------
    print ADDR vendorID
    print chr$("  Family ")
    print ustr$(displayFamily)
    print chr$("  Model ")
    print ustr$(displayModel)
    print chr$("  Stepping ")
    print ustr$(steppingID)
    print chr$(NL)

    ; ----------------------------------------------------------
    ; For Intel processors, display the Intel Brand String from
    ; a table. If the brand ID is zero, display a processor
    ; identification based on the family, model, and features.
    ;
    ; The table is adapted from the IA-32 Intel Architecture
    ; Software Developer's Manual Volume 2A, 253666-015,
    ; April 2005, Table 3-19.
    ; ---------------------------------------------------------
    .IF vendor == VENDOR_INTEL
        print chr$("Intel Brand String: ")
        SWITCH brandID
            CASE 0
                print chr$("NA")
                SWITCH family
                    CASE 4
                        print chr$(", processor is 486")
                    CASE 5
                        .IF cpufeat(MMX)
                            print chr$(", processor is Pentium MMX")
                        .ELSE
                            print chr$(", processor is Pentium I")
                        .ENDIF
                    CASE 6
                        .IF cpufeat(SSE)
                            print chr$(", processor is Pentium III")
                        .ELSEIF cpufeat(MMX)
                            print chr$(", processor is Pentium II")
                        .ELSE
                            print chr$(", processor is Pentium Pro")
                    .ENDIF
                ENDSW
                print chr$(NL)
            CASE 1
                print chr$("Intel(R) Celeron(R) processor"),NL
            CASE 2
                print chr$("Intel(R) Pentium(R) III processor"),NL
            CASE 3
                .IF signature == 6B1h
                    print chr$("Intel(R) Celeron(R) processor"),NL
                .ELSE
                    print chr$("Intel(R) Pentium(R) III Xeon(TM) processor"),NL
                .ENDIF
            CASE 4
                print chr$("Intel(R) Pentium(R) III processor"),NL
            CASE 6
                print chr$("Mobile Intel(R) Pentium(R) III processor-M"),NL
            CASE 7
                print chr$("Mobile Intel(R) Celeron(R) processor"),NL
            CASE 8
                print chr$("Intel(R) Pentium(R) 4 processor"),NL
            CASE 9
                print chr$("Intel(R) Pentium(R) 4 processor"),NL
            CASE 0Ah
                print chr$("Intel(R) Celeron(R) processor"),NL
            CASE 0Bh
                .IF signature == 0F13h
                    print chr$("Intel(R) Xeon(TM) processor MP"),NL
                .ELSE
                    print chr$("Intel(R) Xeon(TM) processor"),NL
                .ENDIF
            CASE 0Ch
                print chr$("Intel(R) Xeon(TM) processor MP"),NL
            CASE 0Eh
                .IF signature == 0F13h
                    print chr$("Intel(R) Xeon(TM) processor"),NL
                .ELSE
                    print chr$("Mobile Intel(R) Pentium(R) 4 processor-M"),NL
                .ENDIF
            CASE 0Fh
                print chr$("Mobile Intel(R) Celeron(R) processor"),NL
            CASE 13h
                print chr$("Mobile Intel(R) Celeron(R) processor"),NL
            CASE 16h
                print chr$("Intel(R) Pentium(R) M processor"),NL
            CASE 17h
                print chr$("Mobile Intel(R) Celeron(R) processor"),NL
            DEFAULT
                print chr$("NA, unknown Brand ID"),NL
        ENDSW
    .ENDIF

    ; -----------------------------------------------------------
    ; For AMD processors, display the name string, if available,
    ; or a processor identification based on the family.
    ; -----------------------------------------------------------
    .IF vendor == VENDOR_AMD
        print chr$("AMD Name String: ")
        .IF maxCpuidInputEx >= 80000004h
            print ADDR nameString,NL
        .ELSE
            .IF family == 4
                print chr$("NA, processor is 486/5x86"),NL
            .ELSE
                print chr$("NA, processor is K5"),NL
            .ENDIF
        .ENDIF
    .ENDIF   

    print chr$("Features: ")
    .IF cpufeat(FPU)
        print "FPU"
    .ENDIF
    .IF cpufeat(TSC)
        print " TSC"
    .ENDIF
    .IF cpufeat(CX8)
        print " CX8"
    .ENDIF
    .IF cpufeat(CMOV)
        print " CMOV"
    .ENDIF
    .IF cpufeat(CLFSH)
        print " CLFSH"
    .ENDIF
    .IF cpufeat(FXSR)
        print " FXSR"
    .ENDIF
    .IF cpufeat(HTT)
        print " HTT"
    .ENDIF   
    .IF cpufeat(MMX)
        print " MMX"
    .ENDIF
    .IF cpufeat(SSE)
        print " SSE"
    .ENDIF
    .IF cpufeat(SSE2)
        print " SSE2"
    .ENDIF
    .IF cpufeat(SSE3)
        print " SSE3"
    .ENDIF
    print chr$(NL)

  fini:
    ret
IdentifyCPU endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start



[attachment deleted by admin]
eschew obfuscation

Phil

C:\ASM\test>IdCPU
GenuineIntel  Family 6  Model 8  Stepping 6
Intel Brand String: Intel Pentium III processor
Features: FPU TSC CX8 CMOV FXSR MMX SSE


Nice! Thanks for the fine code!

RuiLoureiro


GenuineIntel  Family 6  Model 8  Stepping 6
Intel Brand String: Intel Pentium III processor
Features: FPU TSC CX8 CMOV FXSR MMX SSE

Thanks Michael

chep

H:\Dev\Asm\IdCPU>idcpu
AuthenticAMD  Family 6  Model 3  Stepping 0
AMD Name String: AMD Duron(tm) Processor
Features: FPU TSC CX8 CMOV FXSR MMX


Well done.

Mark Jones

It looks like I've been lying about my CPU!


AuthenticAMD  Family 6  Model 10  Stepping 0
AMD Name String: AMD Athlon(tm) XP 2500+
Features: FPU TSC CX8 CMOV FXSR MMX SSE


I thought it was an 1800+ but realize that I was thinking of the literal clock speed. :)

Nice job. :U
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

hutch--

Michael,

Great stuff.  :U

This is the info from my Prescott.


GenuineIntel  Family 15  Model 2  Stepping 5
Intel Brand String: Intel Pentium 4 processor
Features: FPU TSC CX8 CMOV CLFSH FXSR HTT MMX SSE SSE2
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

roticv

You missed out my processor


GenuineIntel  Family 15  Model 3  Stepping 4
Intel Brand String: NA, processor is
Features: FPU TSC CX8 CMOV CLFSH FXSR HTT MMX SSE SSE2 SSE3


It's a Celeron btw

Phil

roticv: SSE3 -- what is that? Does this historic link, http://www.geek.com/procspec/features/sse3/,  that I discovered with a Google search apply? I'm also not familiar yet with TSC, CX8, CLFSH, or FXSR so I've got some research to do. Just thought I'd ask because you seem to have a Celeron with SSE3 and I figured that you might know.

dsouza123


AuthenticAMD  Family 6  Model 4  Stepping 2
AMD Name String: AMD Athlon(tm) Processor
Features: FPU TSC CX8 CMOV FXSR MMX


Athlon 1200 (Thunderbird)

It is an amazing piece of code.

Using WCPUID 3.3
the standard info is Family 6 Model 4 Stepping 2
the extended info is Family 7 Model 4 Stepping 2

Not sure if IdCPU is showing standard or attempting to show extended Family info,
I'd tried reassembling to figure out which, but had errors with msvcrt.inc (2) and macros.inc (5).

GregL

It got my Pentium III Coppermine right.

GenuineIntel  Family 6  Model 8  Stepping 10
Intel Brand String: Intel Pentium III processor
Features: FPU TSC CX8 CMOV FXSR MMX SSE



roticv

Phil,

You can call my Celeron a stripped down verison of P4. It has the all the features of a P4 but a smaller cache, so I have to pay lesser for it.  :toothy

Anyway SSE3 was only introduced by Intel in April 2004, and I think Hutch's P4 is much older than that. Therefore his P4 does not come with SSE3.

hutch--

Yep,

Thats right, its a 2.8 gig Prescott that would be 9 months old or so and it was before SSE3.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

Thanks for the testing, guys. There are apparently at least two problems left to fix.

The names for the feature bits are from the Intel documentation. I tried to select features that would be generally useful for optimization purposes, and provide macros to make detection of the features easy.

FPU: Floating Point Unit On-Chip

TSC: Time Stamp Counter (so RDTSC instruction supported)

CX8: CMPXCHG8B instruction supported (similar to the CMPXCHG introduced with the 486, but acts on 64 bits)

CMOV: Conditional Move instruction supported (and if FPU then FCOMI and FCMOV supported)

CLFSH: CLFLUSH instruction supported (Flush Cache Line)

FXSR: FXSAVE and FXSTOR instructions supported (fast save and restore of floating point context)

HTT: Hyper-Threading Technology supported
eschew obfuscation

doomsday

Works for me.
AuthenticAMD  Family 15  Model 7  Stepping 10
AMD Name String: AMD Athlon(tm) 64 Processor 3500+
Features: FPU TSC CX8 CMOV CLFSH FXSR MMX SSE SSE2


Quote from: MichaelWCMOV: Conditional Move instruction supported (and if FPU then FCOMI and FCMOV supported)
Does anyone know of any x86 that supports CMOVxx but doesn't have a FPU?

regards,
-Brent

MichaelW

I updated my initial post and attachment to a new version that should correct at least one of the problems.

I changed the code to use the family and extended family returned by function 80000001h, rather than function 1, for the AMD processors only, based on this from the AMD Processor Recognition Application Note, rev 3.12, August 2004:
Quote
On all AMD-K6® and AMD Athlon, AMD Sempron™ Model 8, and AMD Duron™ processors, the family number returned by extended function 8000_0001h is equal to the family number returned by standard function 1 + 1. For instance, for the AMD-K6 processor (Model 8), the family number returned by standard function 1 is 0101b (05h) and that returned by extended function 8000_0001h is 0110b (06h); for the AMD Athlon processor Model 6, the standard function returns family 0110b (06h) and the extended function returns 0111b (07h). While differences are small, they are important; for certain purposes, the use of the family number returned by the extended function may be required, rather than that returned by the standard function.

On all AMD Athlon 64, AMD Sempron Model 10, and AMD Opteron processors, and all AMD processors produced prior to AMD-K6, the values returned for the processor signature are identical for both standard function 1 and extended function 8000_0001h.

I corrected the handling of the extended family based on the most recent Intel documentation, which unlike the older documentation almost agrees with the AMD documentation.

I'm not sure what the problem is with roticv's Celeron. AFAIK all recent Intel x86 processors should return a brand ID > 0. Perhaps the processor is an engineering sample.

I made substantial changes, so I would appreciate it if those of you who tested the initial version would run the new one and let me know if anything is broken.
eschew obfuscation