;CPU-Y v0.03.2, developed by Mat Quasar (aka fliermate), 2025/5
;
;Reference:
; - https://board.flatassembler.net/topic.php?t=15628
; - https://codeby.net/threads/cpuid-identifikacija-processora.78279/
; - https://board.flatassembler.net/topic.php?t=23697
; - https://learn.microsoft.com/en-us/windows/win32/controls/create-a-simple-list-box
; - https://board.flatassembler.net/topic.php?t=23853
;
; Update: 11 Apr 2025 - XP style
;
; Version history: v0.01 - Initial release
;                  v0.02 - Added "Processor Features"
;                  v0.03 - Added "CPU Speed"
;                  v0.03.1 - Renamed to "TSC Speed"
;                          - Used "wsprintf" Win32 API for itoa function
;                  v0.03.2 - Added explanation to CPU Cores for Intel
;
format PE GUI 4.0
include 'win32a.inc'

IDD_MAIN        = 100
IDC_CPUNAME     = 101
IDC_CORES       = 102
IDC_CPUSPEED    = 105
IDC_FEATURES    = 103
IDC_OK          = 104
IDM_MAIN        = 200

PF_MMX_INSTRUCTIONS_AVAILABLE = 3
PF_SSE3_INSTRUCTIONS_AVAILABLE= 13
PF_SSSE3_INSTRUCTIONS_AVAILABLE =36
PF_SSE4_1_INSTRUCTIONS_AVAILABLE =37
PF_SSE4_2_INSTRUCTIONS_AVAILABLE =38
PF_AVX_INSTRUCTIONS_AVAILABLE =39
PF_AVX2_INSTRUCTIONS_AVAILABLE = 40
PF_AVX512F_INSTRUCTIONS_AVAILABLE =41

section '.text' code readable executable

  entry $

        mov     eax, 0x80000002
        cpuid
        mov     dword [_name], eax
        mov     dword [_name + 4], ebx
        mov     dword [_name + 8], ecx
        mov     dword [_name + 12], edx
        mov     eax, 0x80000003
        cpuid
        mov     dword [_name + 16], eax
        mov     dword [_name + 20], ebx
        mov     dword [_name + 24], ecx
        mov     dword [_name + 28], edx
        mov     eax, 0x80000004
        cpuid
        mov     dword [_name + 32], eax
        mov     dword [_name + 36], ebx
        mov     dword [_name + 40], ecx
        mov     dword [_name + 44], edx

        mov      eax, 1
        cpuid
        shr      ebx, 16
        and      ebx, 0xFF
        cinvoke  wsprintf, _number, _fmt, ebx

        invoke  IsProcessorFeaturePresent, PF_MMX_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_mmx + 11], ebx

        invoke  IsProcessorFeaturePresent, PF_SSE3_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_sse3 + 11], ebx

        invoke  IsProcessorFeaturePresent, PF_SSSE3_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_ssse3 + 11], ebx

        invoke  IsProcessorFeaturePresent, PF_SSE4_1_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_sse41 + 11], ebx

        invoke  IsProcessorFeaturePresent, PF_SSE4_2_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_sse42 + 11], ebx

        invoke  IsProcessorFeaturePresent, PF_AVX_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_avx + 11], ebx

        invoke  IsProcessorFeaturePresent, PF_AVX2_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_avx2 + 11], ebx

        invoke  IsProcessorFeaturePresent, PF_AVX512F_INSTRUCTIONS_AVAILABLE
        or      eax, eax
        cmovne  ebx, dword [_yes]
        cmove   ebx, dword [_no]
        mov     dword [_avx512f + 11], ebx

        mov     ecx,2        ; cycle
.redo:
        push    ecx
        xor     eax,eax
        cpuid               ; clear cpu pipeline
        rdtsc
        push    eax
        invoke  Sleep,1000   ; wait 1-sec..
        rdtsc
        pop     ebx
        sub     eax,ebx      ; difference
        pop     ecx
        dec     ecx
        jnz     .redo           ; RAX = tsc value
        cdq
        mov     ebx, 1000000
        idiv    ebx
        cinvoke  wsprintf, _buf, _fmt, eax

        invoke  GetModuleHandle,0
        invoke  DialogBoxParam,eax,IDD_MAIN,HWND_DESKTOP,DialogProc,0
        invoke  ExitProcess,0

proc DialogProc hwnddlg,msg,wparam,lparam
        push    ebx esi edi
        cmp     [msg],WM_INITDIALOG
        je      .wminitdialog
        cmp     [msg],WM_CLOSE
        je      .wmclose
        xor     eax,eax
        jmp     .finish
  .wminitdialog:
        ;invoke  GetDlgItem,[hwnddlg],IDC_CPUNAME
        ;mov     [hwndcpuname],eax
        ;invoke  GetDlgItem,[hwnddlg],IDC_CORES
        ;mov     [hwndcores],eax
        invoke  GetDlgItem,[hwnddlg],IDC_FEATURES
        mov     [hwndfeatures],eax

        invoke  SetDlgItemText,[hwnddlg],IDC_CPUNAME,_name
        invoke  SetDlgItemText,[hwnddlg],IDC_CPUSPEED,_buf
        invoke  SetDlgItemText,[hwnddlg],IDC_CORES,_number
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0, _mmx
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0,_sse3
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0,_ssse3
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0,_sse41
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0,_sse42
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0,_avx
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0,_avx2
        invoke  SendMessage, [hwndfeatures], LB_ADDSTRING,0,_avx512f
;        invoke  SendMessage[hwndfeatures], LB_SETITEMDATA,1,0

        ;invoke  SendMessage,[hwndcpuname],EM_SETSEL,0,-1
        ;invoke  SetFocus,[hwndcpuname]
        jmp     .processed
  .wmclose:
        invoke  EndDialog,[hwnddlg],0
  .processed:
        mov     eax,1
  .finish:
        pop     edi esi ebx
        ret
endp

section '.data' data readable writeable

  _mmx        db 'MMX    ',9,'-       ',0
  _sse3       db 'SSE3   ',9,'-       ',0
  _ssse3      db 'SSSE3  ',9,'-       ',0
  _sse41      db 'SSE4.1 ',9,'-       ',0
  _sse42      db 'SSE4.2 ',9,'-       ',0
  _avx        db 'AVX    ',9,'-       ',0
  _avx2       db 'AVX2   ',9,'-       ',0
  _avx512f    db 'AVX512F',9,'-       ',0  ;11th pos
  _yes        db 'Yes '
  _no         db 'No  '
  hwndcpuname dd ?
  hwndcores   dd ?
  hwndfeatures dd ?
  _fmt        db '%d',0
  _buf        rb 20
              db 0
  _number     rb 10
              db 0
  _name       rb 48


section '.idata' import readable

  library kernel,'KERNEL32.DLL',\
          user,'USER32.DLL'

  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         IsProcessorFeaturePresent, 'IsProcessorFeaturePresent',\
         Sleep, 'Sleep', \
         ExitProcess,'ExitProcess'

  import user,\
         DialogBoxParam,'DialogBoxParamA',\
         EndDialog,'EndDialog' ,\
         SetDlgItemText,'SetDlgItemTextA',\
         GetDlgItemText,'GetDlgItemTextA',\
         GetDlgItem,'GetDlgItem',\
         SendMessage,'SendMessageA',\
         SetFocus,'SetFocus', \
         wsprintf, 'wsprintfA'

section '.rsrc' resource data readable

  directory RT_DIALOG,dialogs,\
            RT_MANIFEST,manifest

  resource dialogs,\
           IDD_MAIN,LANG_ENGLISH+SUBLANG_DEFAULT,main_dialog

  dialog main_dialog,'CPU-Y v0.03.2',0,0,400,250,WS_CAPTION+WS_POPUP+WS_SYSMENU+DS_MODALFRAME
     dialogitem 'STATIC','CPU Name',-1,10,10,70,15,WS_VISIBLE
     dialogitem 'EDIT','0',IDC_CPUNAME,80,10,250,15,WS_VISIBLE+WS_BORDER+WS_TABSTOP+ES_AUTOHSCROLL+ES_READONLY
     dialogitem 'STATIC','TSC',-1,10,30,70,15,WS_VISIBLE
     dialogitem 'EDIT','0',IDC_CPUSPEED,80,30,50,15,WS_VISIBLE+WS_BORDER+WS_TABSTOP+ES_AUTOHSCROLL+ES_READONLY
     dialogitem 'STATIC','MHz',-1,135,30,30,15,WS_VISIBLE
     dialogitem 'STATIC','CPU Cores',-1,10,50,70,15,WS_VISIBLE
     dialogitem 'EDIT','0',IDC_CORES,80,50,50,15,WS_VISIBLE+WS_BORDER+WS_TABSTOP+ES_AUTOHSCROLL+ES_READONLY
     dialogitem 'STATIC','(Intel: Maximum number of logical processors supported)',-1,135,50,200,15,WS_VISIBLE
     dialogitem 'STATIC','Processor Features',-1,10,80,70,15,WS_VISIBLE
     dialogitem 'LISTBOX','0',IDC_FEATURES,10,95,330,120,WS_VISIBLE+WS_TABSTOP+WS_BORDER+LBS_USETABSTOPS
  enddialog

  resource  manifest,\
            1, LANG_NEUTRAL, winxp

resdata winxp
      ;  file 'manifest.xml'
db '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',13,10
db '<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">',13,10
db '<assemblyIdentity',13,10
    db 'version="1.0.0.0"',13,10
    db 'processorArchitecture="X86"',13,10
    db 'name="CompanyName.ProductName.Application"',13,10
    db 'type="win32"',13,10
db  '/>',13,10
db '<description>Your application description here.</description>',13,10
db '<dependency>',13,10
    db '<dependentAssembly>',13,10
        db '<assemblyIdentity',13,10
            db 'type="win32"',13,10
            db  'name="Microsoft.Windows.Common-Controls"',13,10
            db 'version="6.0.0.0"',13,10
            db 'processorArchitecture="X86"',13,10
            db 'publicKeyToken="6595b64144ccf1df"',13,10
            db 'language="*"',13,10
       db  '/>',13,10
    db '</dependentAssembly>',13,10
db '</dependency>',13,10
db '</assembly>'
endres
