[comp.sys.intel] Software identification of iAPX80386SX,DX and iAPX80486 CPUs

realmer@wet.UUCP (Sean B. Straw) (09/04/90)

	Personally, I don't know what the fuss is with trying to identify the
Intel CPUs from software - it's quite simple really.  It's all in the prefetch
queue (literally).  I have assembler code that has successfully identified the
iAPX80386SX from the iAPX80386DX (which I could already identify), and the
iAPX80486 is identified as well through this means (although it is a rather
particular creature).
	The Intel specified way is really ... *ssbackwards (as my personal
engineering beliefs dictate - sorry to all of you Intel engineers), as, if you
think about it, application software hasn't a hope of having control of the
CPU right after a CPU RESET, and when it finally does gain control, the EAX
register sure as hell isn't what the CPU set it to after RESET.

	The trick with the prefetch queue is changing a value in the code
segment, that will affect how the CPU will perform it's duties.  If the
instruction is outside of the prefetch queue, then the CPU will act on the
change you made.  However, if the instruction is inside of the prefetch queue
when you make the alteration, then the CPU will *not* act on the change
(unless you entered the code again, at which time the CPU would have re-read
the memory).  The following assembler (and it must be written in assembler)
real-mode code fragment demonstrates this function:

QUEUESIZE	EQU	12		; Known size of the CPU you are
					;  testing for.  This is the key
					;  value when determining the CPU
					;  type.  You should experiment
					;  with this value yourself to
					;  determine which is accurrate for
					;  the CPU you are working with...
					;  I will make a later posting with
					;  the values for the various
					;  CPU types (this code is slightly
					;  different (better) than what I
					;  have put to use already).

	PUSHF				; Preserve Flags
	PUSH	DS			; .. DS
	PUSH	AX			; .. AX

	PUSH	CS			; Get CS ...
	POP	DS			; .. Into DS
	MOV	AL,BYTE PTR MODIFY	; Get original value of
					;  modified instruction.

	CLI				; Disable software interrupts
					;  (you may wish to disable NMI and
					;  Watchdog timer as well...)

	CALL	FAR PTR ID_CPU		; This should force a re-read of the
					;  prefetch queue.  Used to be a JMP
					;  instruction would do it, but the
					;  IAPX80486 is a bit optimized...

	STI				; Reenable software interrupts

	MOV	BYTE PTR MODIFY,AL	; Restore original value of
					;  modified instruction

	POP	AX			; Restore AX
	POP	DS			; .. DS

	JC	SMALLQUEUE		; Branch if the CPU has a smaller
					;  queue.
LARGEQUEUE:
;
;	Set your flags for the condition of a large prefetch queue.
;

;	(Your routine goes here)

	JMP	ID_EXIT			; And leave this area.

SMALLQUEUE:
;
;	Set your flags for the condition of a small prefetch queue.
;

;	(Your routine goes here)

	JMP	ID_EXIT			; And leave this area.

EVEN					; Align on EVEN address boundary
ID_CPU	PROC	FAR
;
;	(On entry here, the first instruction should be at the head of
;	the prefetch queue).
;
	MOV	BYTE PTR MODIFY,0F8h	; CLC instruction.

;
;	The following should fill the remainder of the prefetch with
;	NOP instructions, such that the last thing in the queue should
;	be the carry modifying instruction.  If the queue is smaller
;	than the QUEUESIZE, then the CF modifying instruction will fall
;	outside of the prefetch queue, such that the CPU will read the
;	changed instruction into the prefetch, and act on it.  If the
;	instruction is inside of the queue, then the change will not be
;	acted upon (although the memory will be changed).  It is
;	imperative that the preceeding instruction not use a CS:
;	override, but that it use the DS: for its source.  It is my
;	belief (through testing) that the iAPX80486 understands when it's
;	prefetch is being modified via CS: overrides.
;

IF	((QUEUESIZE - 6) GT 0)
	DB	(QUEUESIZE - 6) DUP (090h)	; NOP instructions
ENDIF

MODIFY	LABEL	BYTE
	STC				; Set CF (or be modified to CLC)

	RET				; Return to caller
ID_CPU	ENDP

ID_EXIT:
;
;	(Continue with your normal applcation)
;
	POPF				; Restore Flags


	It should be noted that this fragment of code relies on the
professionally frowned-upon practice of self-modification of code.  It has to
be this way.  I certainly don't write anything else this way, but the prefetch
is an exception to the Cardinal Rule...
	This version of the routine can be called a multiple number of times
as the original value of the MODIFY label (the CF modifier) is preserved and
restored.  This is relatively useless, as you should just set a CPU_ID value
to indicate the CPU you have found, and never call into the routine again...

Should you have a desire or need to obtain a fully-functional assembler module
for the determination of CPUs (all 8086 compatable types I have ever managed
to obtain...), send me email, and perhaps I shall post the module, or respond
directly to you.