;cpu: Identify CPU and FPU type v2.23;
;Copyright (c) 1992-2022 by Takayuki Hosoda. All rights reserved.;
;cpu is free software with ABSOLUTELY NO WARRANTY.;
;This program was assembled by Borland's TASM Ver.3.0.;
;[vendorstring] CPU processor [of id:xxxx] with[out|FPU] fpu;
TRUE            equ     1
FALSE           equ     0
COPYRIGHT       equ     TRUE
PRINT_FEATURE   equ     TRUE
CR              equ     0dh
LF              equ     0ah
MSEOF           equ     1ah
I86             equ     00h
I186            equ     01h
V30             equ     02h
V33             equ     03h
I286            equ     04h
I386            equ     05h
C486            equ     06h
I486            equ     07h
X486            equ     08h
P586            equ     09h
;Pentium        equ     0ah
P686            equ     0bh
;P6 family      equ     0ch
PUNKNOWN        equ     0dh
P786            equ     0eh
;Pentium 4 family equ   0fh
FPU             equ      1
NDP287          equ      2
NDP387          equ      3
INTEL           equ     01h
PUTS    macro   msg
        mov     ah, 09h
        mov     dx, offset msg
        int     21h
        endm
cpuid   macro   op
        mov     eax, op
        db      0fh, 0a2h
        endm
.386P
        CODE    SEGMENT USE16
        ASSUME  CS:CODE,DS:CODE
        ORG     0100H
start:
; initial hack and variables;
fputype         label
fp_status       dw      432dh
signiture       db      50h, 55h, 2dh, 1ah
max_id          db      00h
cputype         db      'X'
        push    cs
        pop     ds
        push    cs
        pop     es
        cld
; print copyright;
        mov     si, 0080h
        lodsb
        and     al, al
        jz      short get_cpu
        puts    copy_right
        mov     ah, 04ch
        int     21h
get_cpu:
        call    check_cpu
        mov     byte ptr cputype, al
print_vendor:
        mov     al, byte ptr max_id
        cmp     al, 1
        jb      short print_cpu
        puts    vdr_id
print_cpu:
        mov     bl, byte ptr cputype
        xor     bh, bh
        mov     bl, byte ptr [offset cpu_tbl + bx]
        mov     dx, offset cpu_tbl
        add     dx, bx
        mov     ah, 09h
        int     21h
        puts    processor
        mov     al, byte ptr max_id
        cmp     al, 2
        jb      @1
        puts    of_id
        mov     ebx, dword ptr signiture
        mov     di, offset fms_num
        call    print_hex
@1:
        puts    with
get_fpu:
        call    check_fpu
        mov     byte ptr fputype, al
; print_fpu;
        or      al, al
        mov     dx, offset nofpu
        jz      short print_fpu
        mov     bl, byte ptr cputype
        cmp     bl, I286
        mov     dx, offset fpu_87
        jb      short print_fpu
        mov     dx, offset fpu_287
        cmp     al, NDP287
        jz      short print_fpu
        mov     dx, offset fpu_onchip
        cmp     bl, I486
        jae     short short print_fpu
        mov     dx, offset fpu_387
        
print_fpu:
        mov     ah, 9
        int     21h
        puts    fpu_det
; print_feature;
        cmp     byte ptr max_id, 1
        jb      short exit
        ; print features;
        puts    feature_flag
        mov     ebx, dword ptr feature
        mov     si, offset edx_feature
        call    show_feature
        mov     ebx, dword ptr xfeature
        or      ebx, ebx
        jz      exit
        puts    feature_cont
        mov     si, offset ecx_feature
        call    show_feature
        jmp     exit
show_feature proc
        or      ebx, ebx
        jz      short end_feature
        test    bl, 1
        jz      short shift_feature
        push    bx
        push    si
        mov     dx, si
        mov     ah, 9
        int     21h
        pop     si
        pop     bx
shift_feature:
        lodsb
        cmp     al, '$'
        jne     short shift_feature
        shr     ebx, 1
        cmp     bl, 0
        jne     short comma
        jmp     short show_feature
comma:
        dec     si
        mov     byte ptr [si], ','
        jmp     short show_feature
end_feature:
        ret
        endp
exit:
        mov     al, byte ptr fputype
        shl     al, 1
        shl     al, 1
        shl     al, 1
        shl     al, 1
        or      al, byte ptr cputype
        mov     ah, 04ch
        int     21h
;input
;  ebx dword ptr variable
;  offset fms_num
print_hex proc
        mov     di, offset fms_num
        mov     cx, 8
print_hex_loop:
        rol     ebx, 4
        mov     al, bl
        and     al, 0fh
        cmp     al,  9
        jbe     @2
        add     al, 'A' - '0' - 10
@2:
        add     al, '0'
        stosb
        loop    print_hex_loop
        puts    fms_num
        ret
endp
check_fpu proc
        ; is fpu;
        mov     si, offset fp_status ; initialize with non-zero
        xor     bx, bx
        fninit
        fnstsw  word ptr [si]
        mov     ax, word ptr [si]
        cmp     al, 0
        jne     short end_fpu ; no fpu
        ; check controll word;
        fnstcw  word ptr [si]
        mov     ax, word ptr [si]
        and     ax, 103fh
        cmp     ax, 3fh
        jne     short end_fpu ; incorrect controll word, no fpu
        mov     bl, 1         ; fpu present
        cmp     byte ptr cputype, i386
        jne     end_fpu
        fld1
        fldz
        fdiv
        fld     st
        fchs
        fcompp
        fstsw   word ptr [si]
        mov     ax, [si]
        mov     bl, 2
        sahf
        jz      short end_fpu ; i8087 or i287 NDP present
        mov     bl, 3         ; i387 NDP present
end_fpu:
        mov     ax, bx
        ret
endp
check_cpu proc
test_8086:
        mov     cl, 33
        mov     al,  1
        shl     al, cl
        or      al, al
        jnz     short test_186
test_v30:
        mov     ax, sp
        pusha
        nop
        nop
        nop
        nop
        nop
        cmp     ax, sp
        jne     short test_v30_end
        mov     al, I86
        ret
test_v30_end:
        popa
test_v33:
        mov     ax, 0100h
        aad     0h
        mov     al, V33
        jz      short nec_v33
        mov     al, V30
nec_v33:
        ret
test_186:
        pushf
        pop     ax
        test    ax, 08000h
        jz      short test_286
        mov     al, I186
        ret
test_286:
        or      ax, 04000h
        push    ax
        popf
        pushf
        pop     ax
        test    ax, 04000h
        jnz     short test_386
        mov     al, I286
        ret
test_386:
        pushfd
        pop     eax
        bts     eax, 18
        push    eax
        popfd
        pushfd
        pop     eax
        bt      eax, 18
        jc      short test_cpuid
        mov     al, I386
        ret
test_cpuid:
        pushfd
        pushfd
        pop     eax
        bts     eax, 21
        push    eax
        popfd
        pushfd
        pop     eax
        popfd
        bt      eax, 21
        jc      short get_vendor ; have CPUID instruction
test_Cx486:
        mov     al, 08h
        add     al, 08h
        and     al, 00h
        daa
        cmp     al, 06h
        mov     al, C486
        je      short cylix_486
        mov     al, I486
cylix_486:
        ret
get_vendor:
        cpuid   0; Highest Function Parameter and Manufacturer ID
        mov     di, offset vdr_id
        mov     dword ptr [di], ebx
        mov     dword ptr [di+4], edx
        mov     dword ptr [di+8], ecx
        or      eax, eax
        pushf
        ; check intel;
        mov     si, offset vdr_id
        mov     di, offset intel_id
        mov     cx, 12
        repe    cmpsb
        or      cx, cx
        jnz     check_end
        mov     byte ptr vendor_flag, INTEL
check_end:
        popf
        jnz     short get_cpuid
        mov     al, X486
        ret
get_cpuid:
        inc     al
        mov     byte ptr max_id, al
        cpuid   1; Processor Info and Feature Bits
        mov     dword ptr signiture, eax
        mov     dword ptr feature, edx
        mov     dword ptr xfeature, ecx
        and     ah, 0fh ; Family ID
        mov     al, X486
        cmp     ah, 5
        jb      pre_586
        mov     al, P586
        cmp     ah, 5
        je      short end_id
        mov     al, P686
        cmp     ah, 6
        je      short end_id
        mov     al, P786
        cmp     ah, 0fh
        jae     short end_id
        mov     al, PUNKNOWN
        ret
end_id:
        add     al, byte ptr vendor_flag
pre_586:
        ret
        endp
of_id           db      " of id:$"
fms_num         db      "        h$"
cpu_tbl         db      cpu86  - cpu_tbl
                db      cpu186 - cpu_tbl
                db      cpv30  - cpu_tbl
                db      cpv33  - cpu_tbl
                db      cpu286 - cpu_tbl
                db      cpu386 - cpu_tbl
                db      cpc486 - cpu_tbl
                db      cpu486 - cpu_tbl
                db      cpx486 - cpu_tbl
                db      cpu586 - cpu_tbl
                db      pentium - cpu_tbl
                db      cpu686 - cpu_tbl
                db      pentiumpro - cpu_tbl
                db      cpuunknown - cpu_tbl
                db      cpu786 - cpu_tbl
                db      pentium4 - cpu_tbl
vdr_id          label
cpu86           db      "8086$"
cpu186          db      "186$"
cpv30           db      "V30 $"
cpv33           db      "V33$"
cpu286          db      "286$"
cpu386          db      "386$"
cpx486          db      "Enhanced "
cpu486          db      "486$"
cpc486          db      "Cx486$"
cpu586          db      "586$"
pentium         db      "Pentium$"
cpu686          db      "686 family$"
pentiumpro      db      "P6 family$"
cpuunknown      db      "Unknown$"
cpu786          db      "786 family$"
pentium4        db      "Pentium 4 family$"
processor       db      " processor$"
with            db      " with$"
nofpu           db      "out$"
fpu_87          db      " 8087$"
fpu_287         db      " 287$"
fpu_387         db      " 387$"
fpu_onchip      db      " on-chip$"
fpu_det         db      " fpu", CR, LF, "$"
vendor_flag     db      0
intel_id        db      "GenuineIntel"
feature         db      0, 0, 0, 0
xfeature        db      0, 0, 0, 0
; FEATURES;
newline         db      CR, LF, "$"
signiture_flag  db      "signiture: $"
feature_flag    db      "features: $"
feature_cont    db      ",$"
edx_feature     db      "fpu$vme$de$pse$"
                db      "tsc$msr$pae$mce$"
                db      "cmpxchg8b$apic$b10$sep$"
                db      "mtrr$pge$mca$cmov$"
                db      "fcmov$pse-36$psn$clfsh$"
                db      "b20$ds$acpi$mmx$"
                db      "fxsr$sse$sse2$ss$"
                db      "htt$tm$ia64$pbe$"
ecx_feature     db      "sse3$pclmulqdq$dtes64$monitor$"
                db      "ds-cpl$vmx$smx$est$"
                db      "tm2$ssse3$cnnxt-id$sdbg$"
                db      "fma$cx16$xtpr$pppdcm$"
                db      "c16$ppcid$dca$sse4.1$"
                db      "sse4.2$x2apic$movbe$poppcnt$"
                db      "tsc-deadline$aes$xsave$"
                db      "osxsave$avx$f16c$rdrnd$hyppervisor$"
dump_feature    db      "b0$b1$b2$b3$b4$b5$b6$b7$"
                db      "b8$b9$b10$b11$b12$b13$b14$b15$"
                db      "b16$b17$b18$b19$b20$b21$b22$b23$"
                db      "b24$b25$b26$b27$b28$b29$b30$b31$"
copy_right      db      "cpu: Identify cpu and fpu v2.23 (Feb. 8, 2022)",CR,LF
                db      "(c) 1992-2022, Takayuki HOSODA.",CR,LF
                db      "cpu is free software with "
                db      "ABSOLUTELY NO WARRANTY.$"
CODE    ENDS
        END     start