Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!usc!apple!agate!darkstar!saturn.ucsc.edu!sidney From: sidney@saturn.ucsc.edu (Sidney Markowitz ) Newsgroups: comp.os.msdos.programmer Subject: Re: Detecting an 80486 Summary: Here's code that does it without trapping Message-ID: <6020@darkstar.ucsc.edu> Date: 15 Aug 90 07:46:47 GMT References: <26a858b9@ralf> <3817@altos86.Altos.COM> <1990Aug14.025550.17669@esegue.segue.boston.ma.us> Sender: usenet@darkstar.ucsc.edu Organization: University of California, Santa Cruz Lines: 125 In article <1990Aug14.025550.17669@esegue.segue.boston.ma.us> johnl@esegue.segue.boston.ma.us (John R. Levine) writes: >In article <3817@altos86.Altos.COM> rcollins@altos86.UUCP (Robert Collins) writes: >>In some article, it was written: >>+} In my Infoplus program, the 286/386/486 are detected by trapping the >>+}invalid opcode interrupt, and then trying instructions. >>[but there are lots of places where this doesn't work very well, either >>because someone else gets the trap, or because some putatively unused opcodes >>do secret things.] > >The Intel 486 Programmer's manual has sample code to tell the difference >among the 8086, 286, 386, and 486 without any trapping at all. ;; Program to distinguish between 8086/80286/80386/80486 ;; It does not trap illegal opcodes, and so works under virtual 8086 ;; systems such as QEMM which cause other methods to crash. ;; ;; Notes: 1) It is possible for a monitor program that is handling a virtual ;; 8086 on an 80386 or 80486 to trap the instructions that access the ;; flags registers and make this code not work. But that would be a lot ;; of work to no purpose, so don't expect a problem in real life systems. ;; 2) This was only tested on an 80386 and an 80486. However, the code ;; for 8086 and 80286 comes from an Intel manual and looks simple ;; ;; Acknowledgements: ;; This program gets its output code from a PC Magazine program that uses ;; invalid opcode trapping and doesn't work under QEMM ;; The code to distinguish 8086 fro 80286 from 80386/486 is adapted from ;; page 22-2 of the Untel 80486 Programmers Manual ;; The code to distiguish between 80386 and 80486 is adapted from pg 3-23 ;; of the same manual. Note that the comments in the manual describe ;; the return value backwards. ;; The comments are my own ;; ;; Sidney Markowitz or .MODEL TINY DOS equ 21H DosPrint equ 09H DosExit equ 4CH .DATA CPUMSG DB 0DH,0AH,'CPU is an 80$' I86 DB '86$' I286 DB '286$' I386 DB '386$' I486 DB '486$' CRLF DB 0DH,0AH,'$' .CODE ORG 100H .386p ;; allow 386 style assembler instructions prog: mov ah,DosPrint mov dx,offset CPUMSG int DOS ;; Test for 8086 by trying to set flags high nibble to 0 ;; On an 8086, the nibble will remain all ones mov dx,offset I86 pushf pop bx and bh,0Fh push bx popf pushf pop ax and ah,0F0h cmp ah,0F0h je TELLCPU ; print out that this is an 8086 ;; Test for 80286 by trying to set flags high nibble to all ones. ;; On an 80286, the nibble will remain all zeroes mov dx,offset I286 or bh,0F0h push bx popf pushf pop ax test ah,0F0h jz TELLCPU ;; Distinguish an 80386 from an 80486 ;; Bit 18 (40000H) of EFLAGS register is used only in the 486 ;; This code flips it and tests if anything happened. ;; ;; mov edx,esp ; Save stack pointer and esp,not 3 ; Align stack pointer to prevent a fault ; when we set the AC flag on a 486 pushfd ; Copy the EFLAGS register pop eax ; into register eax mov ecx,eax ; Save the original EFLAGS value xor eax,40000H ; Flip the AC flag bit push eax ; Try to put the modified value back popfd ; into the EFLAGS register pushfd ; Copy the EFLAGS register again pop eax ; into eax xor eax,ecx ; Compare the old and new AC bits shr eax,18 ; Shift and mask to get the AC comparison bit and eax,1 ; in the low order position of eax push ecx popfd ; Restore EFLAGS that were saved on entry mov esp,edx ; And restore stack pointer to saved value ;; ;; at this point ax = 0 on a 386 ;; ax = 1 on a 486 mov dx,offset I386 test ax,ax jz TELLCPU mov dx,offset I486 ;; output a message with the result, then exit TELLCPU: mov ah,DosPrint int DOS mov ah,DosPrint mov dx,offset CRLF int DOS mov al,0 mov ah,DosExit int DOS end prog ;;;; end of program ;;;;;;;;