列表2.1中的编码演示了怎样确定当前的CPU。它首先测试8088、8086和80286及
其之上芯片的不同之处。在8088中,一个值被推进堆栈后,堆栈指针在写入堆栈之前减
少。从80286开始,则是先写值,然后堆栈指针再减少。通过压入堆栈指针,可以检查写入
堆栈的值,来确定堆栈指针是在值写入之前还是在之后减少。如果要确定当前使用的是
80286、80386或80486,可以尝试设置80286没有使用的标志寄存器位、80286不允许使
用这些位,但80386和80486却允许。如果可以改变这些位的值,则是80386或80486。同
样的方法也可用来区别80386和80486。注意,使用66h大小的覆盖前缀去强制32位标
志寄存器被压入和弹出。这个方法是完全安全的,因为在这时,已经知道它至少是个
80386芯片。
列表2.1
page 6o,132
;checkcpu.asm
; Determines whether the CPU in use is an 8088/8086, an 80286,
an
;80386, or an 80486.Print the CPU and return an errorlevel Of 0,
;2, 3,or4
for 8088/8086, 80286,80386,or 80486, respectively.
.model small
.Stack
. data
say86
db
"8088 or 8086$"
say286 db
" 80286$"
say386 db
"80386$"
say486 db
"80486$"
.code
.startup
checkcpu proc
; The first step is to determine whether the chip is an 8088/8086.
;The key difference is based-on what the CPU does when it executes
;the PUSH instruction.The 8088/8086 decrements the stack
21页
; pointer first and then writes the saved value to the stack. The
; 80286, 80386, and 80486 write the value to the stack and then
; decrement the stack pointer. Thus, when SP is pushed and the
; pushed value is popped off, the value popped off equals the
; current stack pointer, unless the chip is an 8088 or 8086.
push
sp
pop ax
cmp ax,sp
; if values are not the same,
jne is_86 , it is 8088/8086
; The second step is to detecmine whether the chip is an 80286.
; The key diffecence is the IOPL bits in the flags cegister;
; the 80386 and 80486 have them, and the 80286 does not. The
; 80286 does not let them be Set; the 80386 and 80486 do.
pushf
pop ax ; get flags in ax .
or ax,03000h ; set IOPL bits
push ax
; stuff them back
popf , pop flags--this is where the 80286
; will put them back the way they were
pushf
pop ax ; get flags in ax
test ax,03000h ; if the IOPL bits are reset, the chip
jz iS_286 ; is an 80286
; The third Step is to determine Whether the chip iS an 80386.
; The key difference iS the alignment check bit in the flags
; register; the 80486 has one, and the 80386 does not. The 80386
; does not let you set that bit, but the 80486 does.
db 66h ; (32 bit instruction)
pushf
pop ax ; read low word of flags
and ax,00FFFh ; clear IOPL bits- -level zero
pop dx , read high word
or dx,00004h ; set alignment check bit
push dx ; push flags back
push ax
db 66h ; (32-bit instruction)
popf ; pop flags register- -this is where
; the 80386 undoes your work
db 66h ; (32-bit instruction)
pushf ; push flags back
pop ax ; read what you did
pop dx ; find out if the CPU reset the
test dx,4 ; alignment check bit
jz iS_386 ; if it did, the chip iS an 80386
is_486:
mov
dx,offset say486
mov al,4 ; errorlevel 4
jmp sayso
is_386:
mov dx, offset say386
mov al,3 ; errorlevel 3
jmp sayso
iS_286:
mov dx,offset say286
mov al,2 , errorlevel 2
22页
jmp
saySo
is_86:
mov
dx ,offset say86
mov
al,0
;
errorlevel 0
sayso:
push
ax
;save errorlevel
mov
ah,9
;call DOS wPite string function
int
21h
pop
ax
;retrieve
errorlevel
mov
ah , 04Ch
;
terminate process with return code
int
21h
checkcpu endp
end