[comp.sys.ibm.pc] 386 run time testing

mcdonald@uxe.cso.uiuc.edu (10/17/88)

Does anyone out there know a reliable, safe (hopefully not generating
traps) method of having a running program (Microsoft C 5.1) 
determine whether it is running on an 80386 (as opposed to an 8086 or
80286)? I discovered that by coding one 11 line subroutine from my
TeX screen previewer in assembler, using real 32 bit moves and
shifts, that I can get a 35% speed improvement. (I made my non-386
assembler do this by sticking in 
     db  066h
opcode prefixes explicitly.) I would like to put this change in my
distributed version, with a run time test to distinguish it from
the 8086/80286 version in C. 
Doug McDonald (mcdonald@uiucuxe)

nfs@notecnirp.Princeton.EDU (Norbert Schlenker) (10/27/88)

In article <45900168@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes:
>
>Does anyone out there know a reliable, safe (hopefully not generating
>traps) method of having a running program (Microsoft C 5.1) 
>determine whether it is running on an 80386 (as opposed to an 8086 or
>80286)?  ...
>
>Doug McDonald (mcdonald@uiucuxe)

I thought someone else would post this, so I left it sitting for a while.
Below is a routine to do what you ask, in small model for MASM 5.0 and
above.  (There may be syntax errors - I typed it from memory - but the
ideas are correct.)

The code relies on the fact that Intel CPU's have their own idiosyncracies.
Some of the peculiarities are documented, others are NOT.  In particular,
the trick used in the following code to distinguish an 80286 from an 80386
is NOT documented, although it has worked on every '386 I've used.  As far
as I know, the documented methods of distinguishing these CPUs either
operate only at RESET time (which makes them useless for most purposes), or
do not work (i.e. an 80386 looks like an 80286 by Intel documented methods).

Note also that this code does not take into account the oddities of the
NEC V-20/V-30 chips.  If someone has code that can detect them, I would be
pleased to have it.

And finally, I'm not sure what this routine returns if invoked by a task
running in V86 mode on an 80386 (say under Windows/386, or VM/386).


;	cpuid - MASM 5.0+ routine callable from C to determine CPU type
;
;	C:	int cpuid();
;
;	Returns:0 - for an 8086/8088
;		1 - for an 80186/80188
;		2 - for an 80286
;		3 - for an 80386
;
	.MODEL	SMALL

	PUBLIC	_cpuid

	.CODE
_cpuid	PROC
	mov	ax,0		; set default result to 8086/8088

	mov	dx,0		; try to push zero into FLAGS
	push	dx
	popf
	pushf
	pop	dx
	and	dh,0f0h		; mask high nybble
	cmp	dh,0f0h		; if 0000b turns into 1111b,
	je	exit		;   this is an 8086/8088

	inc	ax		; bump result to 80186/80188
	push	sp		; compare stack pointer when pushed
	pop	dx
	cmp	dx,sp		; if SP changed before push,
	jne	exit		;   this is an 80186/80188

	inc	ax		; bump result to 80286
	mov	dx,7000h	; try to push 0111b into high nybble of FLAGS
	push	dx
	popf
	pushf
	pop	dx
	and	dh,70h		; if no bit stayed set,
	jz	exit		;   this is an 80286

	inc	ax		; bump result to 80386

exit:
	ret

_cpuid  ENDP
	END