;===========================================================================
;Procedure: cpu_id
;Purpose:   figures out if the cpu is 386,486,pentium or higher
;Input:     none
;Output:    AL=3,4,5  5 is pentium or higher
;Processing: see code comments
;---------------------------------------------------------------------------
cpu_id proc

; 80286 test A - We'll look at the top four bits of the EFLAGS 
;   register.  On a 286, these bits are always zero.  Later 
;   CPUs allow these bits to be changed.  During this test, 
;   We'll disable interrupts to ensure interrupts do not change 
;   the flags. 

        cli                        ; disable interrupts
        pushf                      ; save the current flags

        pushf                      ; push flags onto stack 
        pop     ax                 ; now pop flags from stack
        or      ax, 0F000h         ; try and set bits 12-15 hi
        push    ax
        popf                       ; set new flags
        pushf
        pop     ax                 ; see if upper bits are 0

        popf                       ; restore flags to original
        sti                        ; enable interrupts
        test    ax, 0F000h         ; were any upper bits 1 ?
        jnz     up386              ; if so, not a 286
        mov     ax,2
        ret

; 80386 test - Bit 18 in EFLAGS is not settable on a 386, but is
;   changeable on the 486 and later CPUs.  Bit 18 is used to 
;   flag alignment faults. During this test, we'll disable 
;   interrupts to ensure no interrupt will change any flags.

up386:
        cli                        ; disable interrupts
        pushfd                     ; push flags to look at
        pop     eax                ; get eflags
        mov     ebx, eax           ; save for later
        xor     eax, 40000h        ; toggle bit 18
        push    eax                                    
        popfd                      ; load modified eflags to CPU
        pushfd                     ; push eflags to look at
        pop     eax                ; get current eflags
        push    ebx                ; push original onto stack
        popfd                      ; restore original flags
        sti                        ; enable interrupts
        xor     eax, ebx           ; check if bit changed 
        jnz     up486              ; changed, so 486 or later
        mov     ax, 3              ; set 80386 flag
        ret

; 80486 test - Bit 21 in EFLAGS is not settable on a 486, but is
;   changeable on the Pentium CPU.  If bit 21 is changeable, it 
;   indicates the CPU supports the CPUID instruction.  It's 
;   amazing it's only taken 10 years to implement the CPUID 
;   instruction, which should have been included from the start!  
;   During this test, we'll disable interrupts to ensure no 
;   interrupt will change any flags. 

up486:
        cli                        ; disable interrupts
        pushfd                     ; push flags to look at
        pop     eax                ; get eflags
        mov     ebx, eax           ; save for later
        xor     eax, 200000h       ; toggle bit 21
        push    eax                                    
        popfd                      ; load modified eflags to CPU
        pushfd                     ; push eflags to look at
        pop     eax                ; get current eflags
        push    ebx                ; push original onto stack
        popfd                      ; restore original flags
        sti                        ; enable interrupts
        xor     eax, ebx           ; check if bit changed 
        jnz     upPentium          ; changed, it's a Pentium
        mov     ax, 4              ; set 80486 flag
        ret
upPentium:
        mov     ax,5
        ret
cpu_id endp
;===========================================================================
;Procedure: cpu_test
;Purpose:   IDs the cpu, bails if CPU isn't at least a 386
;           turns off L1 cache if cpu is 486 or higher
;Input:     none
;Output:    none
;Processing: see code comments
;---------------------------------------------------------------------------
cputype         db      ?               ; storage for cpu type
cro             dd      ?               ; storage for previous CR0 value

check_cpu proc

        call    cpu_id
        mov     cs:[cputype], al
        cmp     al,3
        jb      wimpy_cpu

        ret


wimpy_cpu:
        push    cs
        pop     ds
        lea     dx, not386
        mov     ah, 9
        int     21h
        mov     ax, 4c01h                ;errorlevel 1, not a 386+
        int     21h

not386  db      "Error: A 386 or higher CPU is required.",13,10,"$"
check_cpu endp



restore_cache proc

        cmp     cs:[cputype], 4
        jb      exit_rc

.486
        cli
        mov     eax, [cro]              ; restore previous value
	mov	cr0, eax		; Write back to CR0
        wbinvd                          ; flush da cache
        sti
.386


exit_rc:
        ret
restore_cache endp


disable_cache   proc
        cmp     cs:[cputype], 4
        jb      exit_dc

        ; check command line for "nocacheoff" switch
        ; (as soon as I write something like that!)


        ; turn off L1 cache via CR0 register
        ; store CR0 value for a potential "return to dos" feature

.486
        cli
	mov	eax, CR0		; Make sure cache is disabled
        mov     cs:[cro], eax           ; save state for exit
	or	eax, 060000000H 	; Disable cache
	mov	cr0, eax		; Write back to CR0
        wbinvd                          ; flush da cache
        sti
.386
exit_dc:
        ret
disable_cache   endp

