This commit is contained in:
Jeff Parsons 2015-04-02 23:18:13 -07:00 committed by jeffpar
commit 5575d6e3fa

View file

@ -1,11 +1,12 @@
; Posted in comp.sys.ibm.pc by Michael A. Shiels 8/16/89
; From https://groups.google.com/forum/#!searchin/comp.sys.ibm.pc/single-step$20interrupt/comp.sys.ibm.pc/irWPIdzmCHQ/SyqEtq9mqCEJ ; From https://groups.google.com/forum/#!searchin/comp.sys.ibm.pc/single-step$20interrupt/comp.sys.ibm.pc/irWPIdzmCHQ/SyqEtq9mqCEJ
title CPUID - Determine CPU & NDP Type title CPUID - Determine CPU & NDP Type
page 58,122 page 58,122
name CPUID name CPUID
; ;
; CPUID uniquely identifies each NEC & Intel CPU & NDP. ; CPUID uniquely identifies each NEC & Intel CPU & NDP.
; ;
; Notes on program structure: ; Notes on program structure:
; ;
@ -17,12 +18,12 @@
; ;
; The correspondence between segments and classes is as follows: ; The correspondence between segments and classes is as follows:
; ;
; Segment Class ; Segment Class
; ------- ----- ; ------- -----
; STACK prog ; STACK prog
; DATA data ; DATA data
; MDATA data ; MDATA data
; CODE prog ; CODE prog
; ;
; The segments apprear in the above order in the program source ; The segments apprear in the above order in the program source
; to avoid forward references in the CODE segment to labels in ; to avoid forward references in the CODE segment to labels in
@ -52,280 +53,287 @@
; ;
; Environments tested in: ; Environments tested in:
; ;
; CPU Speed ; CPU Speed
; System in MHz CPU NDP ; System in MHz CPU NDP
; ------ --------- --- --- ; ------ --------- --- ---
; IBM PC AT 6 Intel 80286 Intel 80287 ; IBM PC AT 6 Intel 80286 Intel 80287
; IBM PC AT 9 Intel 80286 Intel 80287 ; IBM PC AT 9 Intel 80286 Intel 80287
; IBM PC AT 6 Intel 80286 none ; IBM PC AT 6 Intel 80286 none
; IBM PC AT 8.5 Intel 80286 none ; IBM PC AT 8.5 Intel 80286 none
; IBM PC 4.77 Intel 8088 Intel 8087-3 ; IBM PC 4.77 Intel 8088 Intel 8087-3
; IBM PC 4.77 Intel 8088* Intel 8087-3 ; IBM PC 4.77 Intel 8088* Intel 8087-3
; IBM PC XT 4.77 Intel 8088 none ; IBM PC XT 4.77 Intel 8088 none
; IBM PC XT 4.77 Intel 8088 Intel 8087-3 ; IBM PC XT 4.77 Intel 8088 Intel 8087-3
; IBM PC Portable 4.77 NEC V20 none ; IBM PC Portable 4.77 NEC V20 none
; COMPAQ 4.77 Intel 8088 none ; COMPAQ 4.77 Intel 8088 none
; COMPAQ 4.77 NEC V20 none ; COMPAQ 4.77 NEC V20 none
; AT&T PC 6300 8 Intel 8086 Intel 8087-2 ; AT&T PC 6300 8 Intel 8086 Intel 8087-2
; AT&T PC 6300 8 NEC V30 Intel 8087-2 ; AT&T PC 6300 8 NEC V30 Intel 8087-2
; Tandy 2000 8 Intel 80186 none ; Tandy 2000 8 Intel 80186 none
; ;
; * = faulty CPU ; * = faulty CPU
; ;
; Program structure: ; Program structure:
; ;
; Group PGROUP: ; Group PGROUP:
; Stack segment STACK, byte-aligned, stack, class 'prog' ; Stack segment STACK, byte-aligned, stack, class 'prog'
; Program segment CODE, byte-aligned, public, class 'prog' ; Program segment CODE, byte-aligned, public, class 'prog'
; Data segment DATA, byte-aligned, public, class 'data' ; Data segment DATA, byte-aligned, public, class 'data'
; Data segment MDATA, byte-aligned, public, class 'data' ; Data segment MDATA, byte-aligned, public, class 'data'
; ;
; Assembly requirements: ; Assembly requirements:
; ;
; Use MASM 1.25 or later. ; Use MASM 1.25 or later.
; With IBM's MASM 2.0 only, use /S to avoid alphabetizing the ; With IBM's MASM 2.0 only, use /S to avoid alphabetizing the segment names.
; segment names. ; Use /r option to generate real NDP code.
; Use /r option to generate real NDP code.
; ;
; MASM CPUID/r; to convert .ASM to .OBJ ; MASM CPUID/r; to convert .ASM to .OBJ
; LINK CPUID; to convert .OBJ to .EXE ; LINK CPUID; to convert .OBJ to .EXE
; EXE2BIN CPUID CPUID.COM to convert .EXE to .COM ; EXE2BIN CPUID CPUID.COM to convert .EXE to .COM
; ERASE CPUID.EXE to avoid executing .EXE ; ERASE CPUID.EXE to avoid executing .EXE
; ;
; Note that the linker doesn't warn about a missing stack segment. ; Note that the linker doesn't warn about a missing stack segment.
; ;
; Author: ; Author:
; ;
; Original code by: Bob Smith May 1985 ; Original code by:
; Qualitas, Inc.
; 8314 Thoreau Dr.
; Bethesda, MD 20817
; ;
; Arthur Zachai suggested the technique to distinguish within the ; Bob Smith May 1985
; 808x and 8018x families by exploiting the difference in the ; Qualitas, Inc.
; length of their pre-fetch instruction queues. ; 8314 Thoreau Dr.
; Bethesda, MD 20817
; ;
; Published in PC Tech Journal - April 1986 - Vol 4 No 4 ; Arthur Zachai suggested the technique to distinguish within the
; 808x and 8018x families by exploiting the difference in the
; length of their pre-fetch instruction queues.
;
; Published in PC Tech Journal - April 1986 - Vol 4 No 4
;
subttl Structures, Records, Equates, & Macros
page
subttl Structures, Records, Equates, & Macros ARG_STR struct
page ARG_BP dw ? ; caller's BP
ARG_STR struc ARG_OFF dw ? ; caller's offset
dw ? ; caller's bp ARG_SEG dw ? ; segment
ARG_OFF dw ? ; caller's offset ARG_FLG dw ? ; flags
ARG_SEG dw ? ; segment ARG_STR ends
ARG_FLG dw ? ; flags
ARG_STR ends
; Record to define bits in the CPU's & NDP's flags' registers ; Record to define bits in the CPU's & NDP's flags' registers
CPUFLAGS record RO:1,NT:1,IOPL:2,OF:1,DF:1,IF:1,TF:1,SF:1,ZF:1,R1:1,AF:1,R2:1,PF:1,R3:1,CF:1 CPUFLAGS record RO:1,NT:1,IOPL:2,OF:1,_DF:1,_IF:1,TF:1,SF:1,ZF:1,R1:1,AF:1,R2:1,PF:1,R3:1,CF:1
NDPFLAGS record R4:3,IC:1,RC:2,PC:2,IEM:1,R5:1,PM:1,UM:1,OM:1,ZM:1,DM:1,IM:1 NDPFLAGS record R4:3,IC:1,RC:2,PC:2,IEM:1,R5:1,PM:1,UM:1,OM:1,ZM:1,DM:1,IM:1
; FLG_PIQL Pre-fetch instruction queue length, 0 => 4-byte ; FLG_PIQL Pre-fetch instruction queue length, 0 => 4-byte, 1 => 6-byte
; 1 => 6-byte ; FLG_08 Intel 808x
; FLG_08 Intel 808x ; FLG_NEC NEC V20 or V30
; FLG_NEC NEC V20 or V30 ; FLG_18 Intel 8018x
; FLG_18 Intel 8018x ; FLG_28 Intel 8028x
; FLG_28 Intel 8028x ; FLG_87 Intel 8087
; FLG_87 Intel 8087 ; FLG_287 Intel 80287
; FLG_287 Intel 80287
; ;
; FLG_CERR Faulty CPU ; FLG_CERR Faulty CPU
; FLG_NERR Faulty NDP switch setting ; FLG_NERR Faulty NDP switch setting
FLG record RSVD:9,FLG_NERR:1,FLG_CERR:1,FLG_NDP:2,FLG_CPU:3 FLG record RSVD:9,FLG_NERR:1,FLG_CERR:1,FLG_NDP:2,FLG_CPU:3
; CPU-related flags ; CPU-related flags
FLG_PIQL equ 001b shl FLG_CPU FLG_PIQL equ 001b shl FLG_CPU
FLG_08 equ 000b shl FLG_CPU FLG_08 equ 000b shl FLG_CPU
FLG_NEC equ 010b shl FLG_CPU FLG_NEC equ 010b shl FLG_CPU
FLG_18 equ 100b shl FLG_CPU FLG_18 equ 100b shl FLG_CPU
FLG_28 equ 110b shl FLG_CPU FLG_28 equ 110b shl FLG_CPU
FLG_8088 equ FLG_08 FLG_8088 equ FLG_08
FLG_8086 equ FLG_08 or FLG_PIQL FLG_8086 equ FLG_08 or FLG_PIQL
FLG_V20 equ FLG_NEC FLG_V20 equ FLG_NEC
FLG_v30 equ FLG_NEC or FLG_PIQL FLG_v30 equ FLG_NEC or FLG_PIQL
FLG_80188 equ FLG_18 FLG_80188 equ FLG_18
FLG_80186 equ FLG_18 or FLG_PIQL FLG_80186 equ FLG_18 or FLG_PIQL
FLG_80286 equ FLG_28 or FLG_PIQL FLG_80286 equ FLG_28 or FLG_PIQL
; NDP-related flags ; NDP-related flags
; 00b shl FLG_NDP Not Present ; 00b shl FLG_NDP Not Present
FLG_87 equ 01b shl FLG_NDP FLG_87 equ 01b shl FLG_NDP
FLG_287 equ 10b shl FLG_NDP FLG_287 equ 10b shl FLG_NDP
BEL equ 07h BEL equ 07h
LF equ 0ah LF equ 0ah
CR equ 0dh CR equ 0dh
EOS equ '$' EOS equ '$'
POPFF macro POPFF macro
local L1,L2 local L1,L2
jmp short L2 ; skip over IRET jmp short L2 ; skip over IRET
L1: L1:
iret ; pop the cs & ip pushed below along iret ; pop the CP & IP pushed below along
; with the flags, our original purpose ; with the flags, our original purpose
L2: L2:
push cs ; prepare for IRET by pushing cs push cs ; prepare for IRET by pushing CS
call L1 ; push ip, jump to IRET call L1 ; push IP, jump to IRET
endm ; POPFF macro endm ; POPFF macro
TAB macro TYP TAB macro TYP
push bx ; save for a moment push bx ; save for a moment
and bx,mask FLG_&TYP ; isolate flags and bx,mask FLG_&TYP ; isolate flags
mov cl,FLG_&TYP ; shift amount mov cl,FLG_&TYP ; shift amount
shr bx,cl ; shift to low-order shr bx,cl ; shift to low-order
shl bx,1 ; times two to index table of words shl bx,1 ; times two to index table of words
mov dx,TYP&MSG_TAB[bx] ; ds:dx => descriptive message mov dx,TYP&MSG_TAB[bx] ; ds:dx => descriptive message
pop bx ; restore pop bx ; restore
mov ah,09h ; function code to display string mov ah,09h ; function code to display string
int 21h ; request dos service int 21h ; request dos service
endm ; TAB macro endm ; TAB macro
page
INT_VEC segment at 0 ; start INT_VEC segment
dd ? ; pointer to INT 00h
INT01_OFF dw ? ; pointer to INT 01h
INT01_SEG dw ?
INT_VEC ends ; end INT_VEC segment
PGROUP group STACK,CODE,DATA,MDATA page
INT_VEC segment at 0 ; start INT_VEC segment
dd ? ; pointer to INT 00h
INT01_OFF dw ? ; pointer to INT 01h
INT01_SEG dw ?
INT_VEC ends ; end INT_VEC segment
PGROUP group STACK,CODE,DATA,MDATA
; The following segment both positions class 'prog' segments lower in ; The following segment both positions class 'prog' segments lower in
; memory than others so the first byte of the resulting .COM file is ; memory than others so the first byte of the resulting .COM file is
; in the CODE segment, as well as satisfies the LINKer's need to have ; in the CODE segment, as well as satisfies the LINKer's need to have
; a stack segment. ; a stack segment.
STACK segment byte stack 'prog' ; start STACK segment STACK segment byte stack 'prog' ; start STACK segment
STACK ends ; end STACK segment STACK ends ; end STACK segment
I11_REC record I11_PRN:2,I11_RSV1:2,I11_COM:3,I11_RSV2:1,I11_DISK:2,I11_VID:2,I11_RSV3:2,I11_NDP:1,I11_IPL:1 I11_REC record I11_PRN:2,I11_RSV1:2,I11_COM:3,I11_RSV2:1,I11_DISK:2,I11_VID:2,I11_RSV3:2,I11_NDP:1,I11_IPL:1
DATA segment byte public 'data' ; start DATA segment DATA segment byte public 'data' ; start DATA segment
assume ds:PGROUP
OLDINT01_VEC label dword ; save area for original INT 01h handler assume ds:PGROUP
OLDINT01_OFF dw ?
OLDINT01_SEG dw ?
NDP_CW label word ; save area for NDP control word OLDINT01_VEC label dword ; save area for original INT 01h handler
db ? OLDINT01_OFF dw ?
NDP_CW_HI db 0 ; high byte of control word OLDINT01_SEG dw ?
NDP_ENV dw 7 dup(?) ; save area for NDP environment
DATA ends NDP_CW label word ; save area for NDP control word
subttl Message Data Area db ?
page NDP_CW_HI db 0 ; high byte of control word
MDATA segment byte public 'data' ; start MDATA segment NDP_ENV dw 7 dup(?) ; save area for NDP environment
assume ds:PGROUP
MSG_START db 'CPUID -- Version 1.0' DATA ends
db CR,LF,CR,LF,EOS subttl Message Data Area
MSG_8088 db 'CPU is an Intel 8088.' page
db CR,LF,EOS
MSG_8086 db 'CPU is an Intel 8086.'
db CR,LF,EOS
MSG_V20 db 'CPU is an NEC V20.'
db CR,LF,EOS
MSG_V30 db 'CPU is an NEC V30.'
db CR,LF,EOS
MSG_80188 db 'CPU is an Intel 80188.'
db CR,LF,EOS
MSG_80186 db 'CPU is an Intel 80186.'
db CR,LF,EOS
MSG_UNK db 'CPU is a maverick -- 80288??.'
db CR,LF,EOS
MSG_80286 db 'CPU is an Intel 80286.'
db CR,LF,EOS
CPUMSG_TAB label word MDATA segment byte public 'data' ; start MDATA segment
dw PGROUP:MSG_8088 ; 000 = Intel 8088
dw PGROUP:MSG_8086 ; 001 = Intel 8086
dw PGROUP:MSG_V20 ; 010 = NEC V20
dw PGROUP:MSG_V30 ; 011 = NEC V30
dw PGROUP:MSG_80188 ; 100 = Intel 80188
dw PGROUP:MSG_80186 ; 101 = Intel 80186
dw PGROUP:MSG_UNK ; 110 = ?
dw PGROUP:MSG_80286 ; 111 = Intel 80286
NDPMSG_TAB label word assume ds:PGROUP
dw PGROUP:MSG_NDPX ; 00 = No NDP
dw PGROUP:MSG_8087 ; 01 = Intel 8087
dw PGROUP:MSG_80287 ; 10 = Intel 80287
MSG_NDPX db 'NDP is not present.' MSG_START db 'CPUID -- Version 1.0'
db CR,LF,EOS db CR,LF,CR,LF,EOS
MSG_8087 db 'NDP is an Intel 8087.' MSG_8088 db 'CPU is an Intel 8088.'
db CR,LF,EOS db CR,LF,EOS
MSG_80287 db 'NDP is an Intel 80287.' MSG_8086 db 'CPU is an Intel 8086.'
db CR,LF,EOS db CR,LF,EOS
MSG_V20 db 'CPU is an NEC V20.'
db CR,LF,EOS
MSG_V30 db 'CPU is an NEC V30.'
db CR,LF,EOS
MSG_80188 db 'CPU is an Intel 80188.'
db CR,LF,EOS
MSG_80186 db 'CPU is an Intel 80186.'
db CR,LF,EOS
MSG_UNK db 'CPU is a maverick -- 80288??.'
db CR,LF,EOS
MSG_80286 db 'CPU is an Intel 80286.'
db CR,LF,EOS
CERRMSG_TAB label word CPUMSG_TAB dw PGROUP:MSG_8088 ; 000 = Intel 8088
dw PGROUP:MSG_CPUOK ; 0 = CPU healthy dw PGROUP:MSG_8086 ; 001 = Intel 8086
dw PGROUP:MSG_CPUBAD ; 1 = CPU faulty dw PGROUP:MSG_V20 ; 010 = NEC V20
dw PGROUP:MSG_V30 ; 011 = NEC V30
dw PGROUP:MSG_80188 ; 100 = Intel 80188
dw PGROUP:MSG_80186 ; 101 = Intel 80186
dw PGROUP:MSG_UNK ; 110 = ?
dw PGROUP:MSG_80286 ; 111 = Intel 80286
MSG_CPUOK db 'CPU appears to be healthy.' NDPMSG_TAB dw PGROUP:MSG_NDPX ; 00 = No NDP
db CR,LF,EOS dw PGROUP:MSG_8087 ; 01 = Intel 8087
MSG_CPUBAD label byte dw PGROUP:MSG_80287 ; 10 = Intel 80287
db BEL,'*** CPU incorrectly allows interrupts '
db 'after a change to SS ***',CR,LF
db 'It should be replaced with a more recent '
db 'version as it could crash the',CR,LF
db 'system at seemingly random times.',CR,LF,EOS
NERRMSG_TAB label word MSG_NDPX db 'NDP is not present.'
dw PGROUP:MSG_NDPSWOK ; 0 = NDP switch set correctly db CR,LF,EOS
dw PGROUP:MSG_NDPSWERR ; 1 = NDP switch set incorrectly MSG_8087 db 'NDP is an Intel 8087.'
db CR,LF,EOS
MSG_80287 db 'NDP is an Intel 80287.'
db CR,LF,EOS
MSG_NDPSWOK db EOS ; no message CERRMSG_TAB dw PGROUP:MSG_CPUOK ; 0 = CPU healthy
MSG_NDPSWERR label byte dw PGROUP:MSG_CPUBAD ; 1 = CPU faulty
db '*** Although there is an NDP installed '
db 'on this sytem, the corresponding',CR,LF
db 'system board switch is not properly set. '
db 'To correct this, flip switch 2 of',CR,LF
db 'switch block 1 on the system board.',CR,LF,EOS
MDATA ends ; end MDATA segment MSG_CPUOK db 'CPU appears to be healthy.'
subttl Main Routine db CR,LF,EOS
page MSG_CPUBAD db BEL,'*** CPU incorrectly allows interrupts '
CODE segment byte public 'prog' ; start CODE segment db 'after a change to SS ***',CR,LF
assume cs:PGROUP,ds:PGROUP,es:PGROUP db 'It should be replaced with a more recent '
org 100h ; skip over PSP db 'version as it could crash the',CR,LF
db 'system at seemingly random times.',CR,LF,EOS
INITIAL proc near NERRMSG_TAB dw PGROUP:MSG_NDPSWOK ; 0 = NDP switch set correctly
mov dx,offset ds:MSG_START ; starting message dw PGROUP:MSG_NDPSWERR ; 1 = NDP switch set incorrectly
mov ah,09h ; function code to display string
int 21h ; request DOS service
call CPUID ; check the CPU's identity MSG_NDPSWOK db EOS ; no message
MSG_NDPSWERR db '*** Although there is an NDP installed '
db 'on this sytem, the corresponding',CR,LF
db 'system board switch is not properly set. '
db 'To correct this, flip switch 2 of',CR,LF
db 'switch block 1 on the system board.',CR,LF,EOS
TAB CPU ; display CPU results MDATA ends ; end MDATA segment
TAB NDP ; display NDP results
TAB CERR ; display CPU ERR results
TAB NERR ; display NDP ERR results
ret ; return to DOS subttl Main Routine
INITIAL endp ; end INITIAL procedure page
subttl CPUID Procedure
page CODE segment byte public 'prog' ; start CODE segment
CPUID proc near ; start CPUID procedure
assume cs:PGROUP,ds:PGROUP,es:PGROUP assume cs:PGROUP,ds:PGROUP,es:PGROUP
org 100h ; skip over PSP
INITIAL proc near
mov dx,offset ds:MSG_START ; starting message
mov ah,09h ; function code to display string
int 21h ; request DOS service
call CPU_ID ; check the CPU's identity
TAB CPU ; display CPU results
TAB NDP ; display NDP results
TAB CERR ; display CPU ERR results
TAB NERR ; display NDP ERR results
ret ; return to DOS
INITIAL endp ; end INITIAL procedure
subttl CPU_ID Procedure
page
CPU_ID proc near ; start CPU_ID procedure
assume cs:PGROUP,ds:PGROUP,es:PGROUP
; This procedure determines the type of CPU and NDP (if any) in use. ; This procedure determines the type of CPU and NDP (if any) in use.
; ;
; The possibilities include: ; The possibilities include:
; ;
; Intel 8086 ; Intel 8086
; Intel 8088 ; Intel 8088
; NEC V20 ; NEC V20
; NEC V30 ; NEC V30
; Intel 80186 ; Intel 80186
; Intel 80188 ; Intel 80188
; Intel 80286 ; Intel 80286
; Intel 8087 ; Intel 8087
; Intel 80287 ; Intel 80287
; ;
; Also checked is whether or not the CPU allows interrupts after ; Also checked is whether or not the CPU allows interrupts after
; changing the SS register segment. If the CPU does, it is faulty ; changing the SS register segment. If the CPU does, it is faulty
@ -337,44 +345,45 @@ CPUID proc near ; start CPUID procedure
; On exit, BX contains flag settings (as defined in FLG record) which ; On exit, BX contains flag settings (as defined in FLG record) which
; the caller can check. For example, to test for an Intel 80286, use ; the caller can check. For example, to test for an Intel 80286, use
; ;
; and bx,mask FLAG_CPU ; and bx,mask FLAG_CPU
; cmp bx,FLG_80286 ; cmp bx,FLG_80286
; je ITSA286 ; je ITSA286
irp XX,<ax,cx,di,ds,es> ; save registers irp XX,<ax,cx,di,ds,es> ; save registers
push XX push XX
endm endm
; test for 80286 -- this CPU executes PUSH SP by first storing SP on ; test for 80286 -- this CPU executes PUSH SP by first storing SP on
; stack, then decrementing it. earlier CPU's decrement, THEN store. ; stack, then decrementing it. earlier CPU's decrement, THEN store.
mov bx,FLG_28 ; assume it's a 286 mov bx,FLG_28 ; assume it's a 286
push sp ; only 286 pushes pre-push SP push sp ; only 286 pushes pre-push SP
pop ax ; get it back pop ax ; get it back
cmp ax,sp ; check for same cmp ax,sp ; check for same
je CHECK_PIQL ; they are, so it's a 286 je CHECK_PIQL ; they are, so it's a 286
; test for 80186/80188 -- 18xx and 286 CPU's mask shift/rotate ; test for 80186/80188 -- 18xx and 286 CPU's mask shift/rotate
; operations mod 32; earlier CPUs use all 8 bits of CL. ; operations mod 32; earlier CPUs use all 8 bits of CL.
mov bx,FLG_18 ; assume it's an 8018x mov bx,FLG_18 ; assume it's an 8018x
mov cl,32+1 ; 18x masks shift counts mod 32 mov cl,32+1 ; 18x masks shift counts mod 32
; note we can't use just 32 in CL ; note we can't use just 32 in CL
mov al,0ffh ; start with all bits set mov al,0ffh ; start with all bits set
shl al,cl ; shift one position if 18x
jnz CHECK_PIQL ; some bits still on,
; so its a 18x, check PIQL
shl al,cl ; shift one position if 18x
jnz CHECK_PIQL ; some bits still on,
; so its a 18x, check PIQL
; test for V20 ; test for V20
mov bx,FLG_NEC ; assume it's an NEC V-series CPU mov bx,FLG_NEC ; assume it's an NEC V-series CPU
call CHECK_NEC ; see if it's an NEC chip call CHECK_NEC ; see if it's an NEC chip
jcxz CHECK_PIQL ; good guess, check PIQL jcxz CHECK_PIQL ; good guess, check PIQL
mov bx,FLG_08 ; it's an 808x
subttl Check Length of Pre-Fetch Instruction Queue
page
mov bx,FLG_08 ; it's an 808x
subttl Check Length of Pre-Fetch Instruction Queue
page
; Check the length of the pre-fetch instruction queue (PIQ). ; Check the length of the pre-fetch instruction queue (PIQ).
; ;
; xxxx6 CPUs have a PIQ length of 6 bytes, ; xxxx6 CPUs have a PIQ length of 6 bytes,
@ -383,140 +392,151 @@ CPUID proc near ; start CPUID procedure
; Self-modifying code is used to distinguish the two PIQ lengths. ; Self-modifying code is used to distinguish the two PIQ lengths.
CHECK_PIQL: CHECK_PIQL:
call PIQL_SUB ; handle via subroutine call PIQL_SUB ; handle via subroutine
jcxz CHECK_ERR ; if CX is 0, INC was not executed, jcxz CHECK_ERR ; if CX is 0, INC was not executed,
; hence PIQ length is 4 ; hence PIQ length is 4
or bx,FLG_PIQL ; PIQ length is 6 or bx,FLG_PIQL ; PIQ length is 6
subttl Check for Allowing Interrupts After POP SS
page subttl Check for Allowing Interrupts After POP SS
page
; Test for faulty chip (allows interrupts after change to SS register) ; Test for faulty chip (allows interrupts after change to SS register)
CHECK_ERR: CHECK_ERR:
xor ax,ax ; prepare to address xor ax,ax ; prepare to address
; interrupt vector segment ; interrupt vector segment
mov ds,ax ; DS points to segment 0 mov ds,ax ; DS points to segment 0
assume ds:INT_VEC ; tell the assembler
cli ; nobody move while we swap assume ds:INT_VEC ; tell the assembler
mov ax,offset cs:INT01 ; point to our own handler cli ; nobody move while we swap
xchg ax,INT01_OFF ; get and swap offset
mov OLDINT01_OFF,ax ; save to restore later
mov ax,cs ; our handler's segment mov ax,offset cs:INT01 ; point to our own handler
xchg ax,INT01_SEG ; get and swap segment xchg ax,INT01_OFF ; get and swap offset
mov OLDINT01_SEG,ax ; save to restore later mov OLDINT01_OFF,ax ; save to restore later
mov ax,cs ; our handler's segment
xchg ax,INT01_SEG ; get and swap segment
mov OLDINT01_SEG,ax ; save to restore later
; note we continue with interrupts disabled to avoid ; note we continue with interrupts disabled to avoid
; an external interrupt occuring during this test ; an external interrupt occuring during this test
mov cx,1 ; initialize a register mov cx,1 ; initialize a register
push ss ; save ss to store back into itself push ss ; save ss to store back into itself
pushf ; move flags pushf ; move flags
pop ax ; ... into ax pop ax ; ... into ax
or ax,mask TF ; set trap flag or ax,mask TF ; set trap flag
push ax ; place onto stack push ax ; place onto stack
POPFF ; ... and then into effect POPFF ; ... and then into effect
; some CPUs effect the trap flag ; some CPUs affect the trap flag
; immediately, some ; immediately, some
; wait one instruction ; wait one instruction
nop ; allow interrupt to take effect nop ; allow interrupt to take effect
POST_NOP: POST_NOP:
pop ss ; change the stack segment register pop ss ; change the stack segment register
; (to itself) ; (to itself)
dec cx ; normal cpu's execute this instruction dec cx ; normal cpu's execute this instruction
; before recognizing the single-step ; before recognizing the single-step
; interrupt ; interrupt
hlt ; we never get here hlt ; we never get here
INT01: INT01:
; Note: IF=TF=0 ; Note: IF=TF=0
; If we're stopped at or before POST_NOP, continue on ; If we're stopped at or before POST_NOP, continue on
push bp ; prepare to address the stack push bp ; prepare to address the stack
mov bp,sp ; hello, Mr. stack mov bp,sp ; hello, Mr. stack
cmp [bp].ARG_OFF,offset cs:POST_NOP ; check offset cmp [bp].ARG_STR.ARG_OFF,offset cs:POST_NOP ; check offset
pop bp ; restore pop bp ; restore
ja INTO1_DONE ; we're done ja INTO1_DONE ; we're done
iret ; return to caller iret ; return to caller
INTO1_DONE: INTO1_DONE:
; restore old INT 01h handler ; restore old INT 01h handler
les ax,OLDINT01_VEC ; ES:AX ==> old INT 01h handler les ax,OLDINT01_VEC ; ES:AX ==> old INT 01h handler
assume es:nothing ; tell the assembler assume es:nothing ; tell the assembler
mov INT01_OFF,ax ; restore offset mov INT01_OFF,ax ; restore offset
mov INT01_SEG,es ; ... and segment mov INT01_SEG,es ; ... and segment
sti ; allow interrupts again (IF=1) sti ; allow interrupts again (IF=1)
add sp,3*2 ; strip ip, cs, and flags from stack add sp,3*2 ; strip IP, CS, and flags from stack
push cs ; setup ds for code below push cs ; setup DS for code below
pop ds pop ds
assume ds:PGROUP ; tell the assembler assume ds:PGROUP ; tell the assembler
jcxz CHECK_NDP ; if cx is 0, the dec cx was executed,
; and the cpu is ok
or bx,mask FLG_CERR ; it's a faulty chip
subttl Check For Numeric Data Processor
page
jcxz CHECK_NDP ; if cx is 0, the dec cx was executed,
; and the cpu is ok
or bx,mask FLG_CERR ; it's a faulty chip
subttl Check For Numeric Data Processor
page
; Test for a Numeric Data Processor -- Intel 8087 or 80287. The ; Test for a Numeric Data Processor -- Intel 8087 or 80287. The
; technique used is passive -- it leaves the NDP in the same state in ; technique used is passive -- it leaves the NDP in the same state in
; which it is found. ; which it is found.
CHECK_NDP: CHECK_NDP:
cli ; protect FNSTENV cli ; protect FNSTENV
fnstenv NDP_ENV ; if NDP present, save fnstenv NDP_ENV ; if NDP present, save
; current environment, ; current environment,
; otherwise, this instruction ; otherwise, this instruction
; is ignored ; is ignored
mov cx,50/7 ; cycle this many times mov cx,50/7 ; cycle this many times
loop $ ; wait for result to be stored loop $ ; wait for result to be stored
sti ; allow interrupts sti ; allow interrupts
fninit ; initialize processor to known state fninit ; initialize processor to known state
jmp short $+2 ; wait for initialization jmp short $+2 ; wait for initialization
fnstcw NDP_CW ; save control word
jmp short $+2 ; wait for result to be stored
jmp short $+2
cmp NDP_CW_HI,03h ; check for NDP initial control word
jne CPUID_EXIT ; no NDP installed
int 11h ; get equipment flags into ax
test ax,mask I11_NDP ; check NDP-installed bit
jnz CHECK_NDP1 ; it's correctly set
or bx,mask FLG_NERR ; mark as in error
fnstcw NDP_CW ; save control word
jmp short $+2 ; wait for result to be stored
jmp short $+2
cmp NDP_CW_HI,03h ; check for NDP initial control word
jne CPUID_EXIT ; no NDP installed
int 11h ; get equipment flags into ax
test ax,mask I11_NDP ; check NDP-installed bit
jnz CHECK_NDP1 ; it's correctly set
or bx,mask FLG_NERR ; mark as in error
CHECK_NDP1: CHECK_NDP1:
and NDP_CW,not mask IEM ; enable interrupts and NDP_CW,not mask IEM ; enable interrupts
; (IEM=0, 8087 only) ; (IEM=0, 8087 only)
fldcw NDP_CW ; reload control word fldcw NDP_CW ; reload control word
fdisi ; disable interrupts (IEM=1) on 8087, fdisi ; disable interrupts (IEM=1) on 8087,
; ignored by 80287 ; ignored by 80287
fstcw NDP_CW ; save control word fstcw NDP_CW ; save control word
fldenv NDP_ENV ; restore original NDP environment fldenv NDP_ENV ; restore original NDP environment
; no need to wait ; no need to wait
; for environment to be loaded ; for environment to be loaded
test NDP_CW,mask IEM ; check interrupt enable mask test NDP_CW,mask IEM ; check interrupt enable mask
; (8087 only) ; (8087 only)
jnz CPUID_8087 ; it changed, hence NDP is an 8087 jnz CPUID_8087 ; it changed, hence NDP is an 8087
or bx,FLG_287 ; NDP is an 80287 or bx,FLG_287 ; NDP is an 80287
jmp short CPUID_EXIT ; exit with falgs in BX jmp short CPUID_EXIT ; exit with falgs in BX
CPUID_8087: CPUID_8087:
or bx,FLG_87 ; NDP is an 8087 or bx,FLG_87 ; NDP is an 8087
CPUID_EXIT: CPUID_EXIT:
irp XX,<es,ds,di,cx,ax> ; restore registers irp XX,<es,ds,di,cx,ax> ; restore registers
pop XX pop XX
endm endm
assume ds:nothing,es:nothing
ret ; return to caller assume ds:nothing,es:nothing
CPUID endp ; end CPUID procedure ret ; return to caller
subttl Check For NEC V20/V30 CPU_ID endp ; end CPU_ID procedure
page
CHECK_NEC proc near subttl Check For NEC V20/V30
page
CHECK_NEC proc near
; The NEC V20/V30 are very compatible with the Intel 8086/8088. ; The NEC V20/V30 are very compatible with the Intel 8086/8088.
; The only point of "incompatibility" is that they do not contain ; The only point of "incompatibility" is that they do not contain
@ -540,25 +560,27 @@ CHECK_NEC proc near
; 55ms and so should interrupt the repeated string instruction at least ; 55ms and so should interrupt the repeated string instruction at least
; once. ; once.
mov cx,0ffffh ; move a lot of data mov cx,0ffffh ; move a lot of data
sti ; ensure timer enabled sti ; ensure timer enabled
; execute multi-prefix instruction. note that the value of ES as ; execute multi-prefix instruction. note that the value of ES as
; well as the direction flag setting is irrelevant. ; well as the direction flag setting is irrelevant.
push ax ; save registers push ax ; save registers
push si push si
rep lods byte ptr es:[si] rep lods byte ptr es:[si]
pop si ; restore pop si ; restore
pop ax pop ax
; on exit: if cx is zero, it's an NEC CPU, otherwise it's an Intel CPU ; on exit: if cx is zero, it's an NEC CPU, otherwise it's an Intel CPU
ret ; return to caller ret ; return to caller
CHECK_NEC endp CHECK_NEC endp
subttl Pre-Fetch Instruction Queue Subroutine
page subttl Pre-Fetch Instruction Queue Subroutine
PIQL_SUB proc near page
PIQL_SUB proc near
; This subroutine discerns the length of the CPU's pre-fetch ; This subroutine discerns the length of the CPU's pre-fetch
; instruction queue (PIQ). ; instruction queue (PIQ).
@ -577,52 +599,47 @@ PIQL_SUB proc near
; the instruction. By that time, the orignial instruction should be in ; the instruction. By that time, the orignial instruction should be in
; a six-byte PIQ byt not a four-byte PIQ. ; a six-byte PIQ byt not a four-byte PIQ.
assume cs:PGROUP,es:PGROUP assume cs:PGROUP,es:PGROUP
@REP equ 3 ; repeat the store this many times @REP equ 3 ; repeat the store this many times
std ; store backwards std ; store backwards
mov di,offset es:LAB_INC+@REP-1 ; change the instructions mov di,offset es:LAB_INC+@REP-1 ; change the instructions
; at ES:DI ; at ES:DI
; and preceding ; and preceding
mov al,ds:LAB_STI ; change to a sti mov al,ds:LAB_STI ; change to a sti
mov cx,@REP ; give the BIU time mov cx,@REP ; give the BIU time
; to pre-fetch instructions ; to pre-fetch instructions
cli ; ensure interrupts are disabled, cli ; ensure interrupts are disabled,
; otherwise a timer tick ; otherwise a timer tick
; could change the PIQ filling ; could change the PIQ filling
rep stosb ; change the instruction rep stosb ; change the instruction
; during execution of this instruction ; during execution of this instruction
; the BIU is refilling the PIQ. The ; the BIU is refilling the PIQ. The
; current instruction is no longer ; current instruction is no longer
; in the PIQ. ; in the PIQ.
; Note at end, CX is 0. ; Note at end, CX is 0.
; The PIQ begins filling here ; The PIQ begins filling here
cld ; restore direction flag cld ; restore direction flag
nop ; PIQ fillers nop ; PIQ fillers
nop nop
nop nop
; The following instruction is beyond a four-byte-PIQ CPU's reach, ; The following instruction is beyond a four-byte-PIQ CPU's reach,
; but within that of a six-byte-PIQ CPU. ; but within that of a six-byte-PIQ CPU.
LAB_INC label byte LAB_INC label byte
inc cx ; executed only if PIQ length is 6 inc cx ; executed only if PIQ length is 6
LAB_STI label byte LAB_STI label byte
rept @REP-1 rept @REP-1
sti ; restore interrupts sti ; restore interrupts
endm endm
ret ; return to caller
assume ds:nothing,es:nothing
PIQL_SUB endp ; end PIQL_SUB procedure
CODE ends ; end code segment ret ; return to caller
if1 assume ds:nothing,es:nothing
%OUT Pass 1 Complete PIQL_SUB endp ; end PIQL_SUB procedure
else
%OUT Pass 2 Complete
endif
end INITIAL ; end CPUID module CODE ends ; end code segment
end INITIAL ; end CPU_ID module