// C file ************************************************************

/*

  I compiled the C part with an old compiler that would generate old
  8086 code so this would run on even an XT. Be careful, many new
  compilers don't support that option, and will generate code that
  will crash old computers.

*/
#include <stdio.h>


/* ---------------------- main() ----------------------- January 13,1995 */
void main(void)
{
   int i;
   static char *cpu_str[]=
      {
      "i86", 
      "i186",
      "i286",
      "i386",
      "i486",
      "i586",
      "i686"
      };

   i=x_processor();

   if ( i > 6 )
      i=6;

   printf("Processor type: %s   CoPro : %s\n", cpu_str[i],
         x_coprocessor() ? "Yes" : "No");


}

// END C file ************************************************************


;-----------------------------------------------------------------------
; MODULE XDETECT
;
; Hardware detection module
;
; Compile with Tasm.
; C callable.
;
;
; ****** XLIB - Mode X graphics library                ****************
; ******                                               ****************
; ****** Written By Themie Gouthas                     ****************
;
;
; modified May, 1993 by Alec Russell - 
; to use TASM high level language extensions
;
; egg@dstos3.dsto.gov.au
; teg@bart.dsto.gov.au
;-----------------------------------------------------------------------

.model medium, c

	 global x_processor            :proc
	 global x_coprocessor          :proc


LOCALS
.386


CPUID   MACRO
        db    0fh,     0A2h
ENDM

	.code


i86       equ 0
i186      equ 1
i286      equ 2
i386      equ 3
i486      equ 4
i586      equ 5



;-----------------------------------------------------------------------
; PC Processor detection routine
;
; C callable as:
;    unsigned int x_processor();
;
;
x_processor PROC
.8086
	pushf                    ; Save flags

	xor  ax,ax		 ; Clear AX
	push ax                  ; Push it on the stack
	popf                     ; Zero the flags
	pushf                    ; Try to zero bits 12-15
	pop  ax                  ; Recover flags
        and  ax,0F000h           ; If bits 12-15 are 1 => i86 or i286
        cmp  ax,0F000h
        jnz  @@not_86_186
        jmp  @@is_86_186

@@not_86_186:

        mov  ax,07000h           ; Try to set bits 12-14
        push ax
        popf
        pushf
        pop  ax
        and  ax,07000h           ; If bits 12-14 are 0 => i286
        jnz   is_not_286
        jmp is_286

is_not_286:


        ; its a 386 or higher

        ; check for 386 by attempting to toggle EFLAGS register
        ; Alignment check bit which can't be changed on a 386
.386
        cli
        pushfd
        pushfd
        pop   eax
        mov  ebx, eax
        xor   eax, 040000h      ; toggle bit 18
        push  eax
        popfd
        pushfd
        pop   eax
        popfd
        sti
        and   eax, 040000h      ; clear all but bit 18
        and   ebx, 040000h      ; same thing
        cmp   eax, ebx
        jne   @@moretest
        mov   ax, i386
        jmp short @@done

        ; is it a 486 or 586 or higher

@@moretest:

        ; check for a 486 by trying to toggle the EFLAGS ID bit
        ; this isn't a foolproof check

        cli
        pushfd
        pushfd
        pop   eax
        mov   ebx, eax
        xor   eax, 0200000h      ; toggle bit 21
        push  eax
        popfd
        pushfd
        pop   eax
        popfd
        sti
        and   eax, 0200000h      ; clear all but bit 21
        and   ebx, 0200000h      ; same thing
        cmp   eax, ebx
        jne   @@moretest2
        mov   ax, i486
        jmp short @@done

@@moretest2:

        ; OK it was probably a 486, but lets double check

        mov   eax, 1
        CPUID
        and   eax, 0f00h
        shr   eax, 8

        mov   ebx, eax
        mov   ax, i586
        cmp   ebx, 5
        je    @@done    ; it was a pentium

        ; it wasn't a 586 so just report the ID

        mov   eax, ebx
        and   eax, 0ffffh

        jmp  short @@done

.8086

is_286:
        mov  ax,i286             ; We have a 286
        jmp  short @@done

@@is_86_186:                       ; Determine whether i86 or i186
        push cx                  ; save CX
        mov  ax,0FFFFh           ; Set all AX bits
        mov  cl,33               ; Will shift once on 80186
        shl  ax,cl               ; or 33 x on 8086
        pop  cx
        jnz  is_186              ; 0 => 8086/8088
is_86:
        mov  ax,i86
        jmp  short @@done
is_186:
        mov  ax,i186
@@done:
	popf

	ret

x_processor endp

.386

 .8086
;-----------------------------------------------------------------------
; PC Numeric coprocessor detection routine
;
; C callable as:
;    unsigned int x_coprocessor();
;
;  Based on an article in PC Tech Journal, Aug 87 by Ted Forgeron
;
;  Returns 1 if coprocessor found, zero otherwise

x_coprocessor PROC

        LOCAL     control:word

	fninit                          ; try to initialize the copro.
	mov    [control],0              ; clear control word variable
        fnstcw control                  ; put control word in memory
	mov    ax,[control]             ;
	cmp    ah,03h                   ; do we have a coprocessor ?
	je     @@HaveCopro              ; jump if yes!
	xor    ax,ax                    ; return 0 since nothing found
	jmp    short @@Done
@@HaveCopro:
	mov    ax,1
@@Done:
	ret

x_coprocessor   endp


end

