home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
PASCAL
/
INFOP125.ZIP
/
INFOPLUS.ASM
next >
Wrap
Assembly Source File
|
1990-08-10
|
15KB
|
586 lines
;--------------------------------------------------------------------
;
; INFOPLUS.ASM
;
; Version 1.25
;
; Four subprograms used by INFOPLUS.PAS:
;
; CPUID - identifies host CPU and NDP (if
; any)
; DISKREAD - reads absolute sectors from disk
; LONGCALL - calls a routine using a CALL FAR
; ATIINFO - for accessing ATI VGAWonder cards
;
; Originally by:
; Steve Grant
; Long Beach, CA
; January 13, 1989
;
; mods by Andrew Rossmann (8/10/90)
;--------------------------------------------------------------------
.286P
.8087
public CPUID, DISKREAD, LONGCALL, ATIINFO
CODE segment byte
; Conditional jumps are all coded with the SHORT qualifier in
; order to minimize the size of the .OBJ file output of Turbo
; Assembler.
;--------------------------------------------------------------------
CPUID proc near
assume cs:CODE, ds:DATA, es:nothing, ss:nothing
; On entry:
;
; BP
; SP => near return address
; offset of a cpu_info_t record
; segment " " " "
; also, the test type byte should be a 'C' or 'N' to execute the
; CPU or NDP tests.
;
; On exit, the cpu_info_t record has been filled in as follows:
;
; byte = CPU type
; word = Machine Status Word
; 6 bytes = Global Descriptor Table
; 6 bytes = Interrupt Descriptor Table
; boolean = segment register change/interrupt flag
; byte = NDP type
; word = NDP control word
; byte = test type (C or N)
mCPU equ byte ptr [bx]
mMSW equ word ptr [bx + 1]
mGDT equ [bx + 3]
mIDT equ [bx + 9]
mchkint equ byte ptr [bx + 15]
mNDP equ byte ptr [bx + 16]
mNDPCW equ word ptr [bx + 17]
mtest equ byte ptr [bx + 19]
f8088 equ 0
f8086 equ 1
fV20 equ 2
fV30 equ 3
f80188 equ 4
f80186 equ 5
f80286 equ 6
f80386 equ 7
f80486 equ 8
funk = 0FFH
false equ 0
true equ 1
push bp
mov bp,sp
push ds
lds bx,[bp + 4]
cmp mtest, 'C'
jnz skipcpu
call cpu
call chkint
skipcpu:
cmp mtest, 'N'
jnz skipndp
call ndp
skipndp:
pop ds
pop bp
ret 4
;--------------------------------------------------------------------
cpu:
; interrupt of multi-prefix string instruction
mov mCPU,funk ;set CPU type to unknown
sti
mov cx,0FFFFH
rep lods byte ptr es:[si]
jcxz short cpu_02
call piq
cmp dx,4
jg short cpu_01
mov mCPU,f8088
ret
cpu_01:
cmp dx,6
jne short cpu_01a
mov mCPU,f8086
cpu_01a:
ret
cpu_02:
; number of bits in displacement register used by shift
mov al,0FFH
mov cl,20H
shl al,cl
or al,al
jnz short cpu_04
call piq
cmp dx,4
jg short cpu_03
mov mCPU,fV20
ret
cpu_03:
cmp dx,6
je cpu_03a
jmp CPUID_done
cpu_03a:
mov mCPU,fV30
ret
cpu_04:
; order of write/decrement by PUSH SP
push sp
pop ax
cmp ax,sp
je short cpu_06
call piq
cmp dx,4
jg short cpu_05
mov mCPU,f80188
ret
cpu_05:
cmp dx,6
jne short CPUID_done
mov mCPU,f80186
ret
;First, grab some tables
cpu_06:
smsw mMSW
sgdt mGDT
sidt mIDT
;!!!!!!!
;!!! Original 286/386 detection code (modified 8/10/90)
;!!! Modified by code supplied by John Levine, apparantly from an Intel
;!!! '486 manual.
;!!!!!!!
pushf ;put flags into CX
pop cx
and cx,0fffh ;mask off upper 4 bits
push cx
popf
pushf
pop ax
and ax,0f000h ;look only at upper 4 bits
cmp ax,0f000h ;88/86 etc.. turn them on
jz badcpu ;not 286/386/486!!!
or cx,0f000h ;force upper 4 bits on
push cx
popf
pushf
pop ax
and ax,0f000h
jz found286 ;bits are zeroed in real mode 286
.386
mov dx,sp ;save current stack position
and sp,not 3 ;dword align to avoid traps
pushfd ;push 32 bit flag
pop eax
mov ecx,eax
xor eax,40000h ;flip AC (alignment check) flag
push eax
popfd
pushfd
pop eax
mov sp,dx
xor eax,ecx ;was bit changed??
test eax,40000h
.286
jz found386 ;if not, is a 386
mov mCPU,f80486 ;must be a 486!!
jmp short CPUID_done
found286:
mov mCPU,f80286
jmp short CPUID_done
found386:
mov mCPU,f80386
jmp short CPUID_done
badcpu:
mov mCPU,funk ;how'd an 8088 get this far?????
CPUID_done:
ret
;--------------------------------------------------------------------
piq:
; On exit:
;
; DX = length of prefetch instruction queue
;
; This subroutine uses self-modifying code, but can
; nevertheless be run repeatedly in the course of the calling
; program.
count = 7
opincdx equ 42H ; inc dx opcode
opnop equ 90H ; nop opcode
mov al,opincdx
mov cx,count
push cx
push cs
pop es
mov di,offset piq_01 - 1
push di
std
rep stosb
mov al,opnop
pop di
pop cx
xor dx,dx
cli
rep stosb
rept count
inc dx
endm
piq_01:
sti
ret
;--------------------------------------------------------------------
chkint:
; save old INT 01H vector
push bx
mov ax,3501H
int 21H
mov old_int01_ofs,bx
mov old_int01_seg,es
pop bx
; redirect INT 01H vector
push ds
mov ax,2501H
mov dx,seg new_int01
mov ds,dx
mov dx,offset new_int01
int 21H
pop ds
; set TF and change SS -- did we trap on following instruction?
pushf
pop ax
or ah,01H ; set TF
push ax
popf
push ss ; CPU may wait one
; instruction before
; recognizing single step
; interrupt
pop ss
chkint_01: ; shouldn't ever trap here
; restore old INT 01H vector
push ds
mov ax,2501H
lds dx,old_int01
int 21H
pop ds
ret
;--------------------------------------------------------------------
new_int01:
; INT 01H handler (single step)
;
; On entry:
;
; SP => IP
; CS
; flags
sti
pop ax ; IP
cmp ax,offset chkint_01
jb short new_int01_03
je short new_int01_01
mov mchkint,false
jmp short new_int01_02
new_int01_01:
mov mchkint,true
new_int01_02:
pop cx ; CS
pop dx ; flags
and dh,0FEH ; turn off TF
push dx ; flags
push cx ; CS
new_int01_03:
push ax ; IP
iret
;--------------------------------------------------------------------
ndp:
fnone equ 0
f8087 equ 1
f80287 equ 2
f80387 equ 3
funk = 0FFH
mov word ptr ndp_cw,0000H
cli
; The next three 80x87 instructions cannot carry the WAIT prefix,
; because there may not be an 80x87 for which to wait. The WAIT is
; therefore emulated with a MOV CX,<value>! LOOP $ combination.
.287
; CPU NDP
fnsave ndp_save ; 14 221
mov cx,(221-6-1)/17+1 ; 4
loop $ ; 17*CX-12
; 17*CX+6
fninit ; 8 8
mov cx,(8-0-1)/17+1 ; 4
loop $ ; 17*CX-12
; 17*CX
fnstcw ndp_cw ; 14 24
mov cx,14h
loop $ ; 17*CX-12
; 17*CX+2
sti
mov ax,ndp_cw
and ax,0f3fh
cmp ax,33fh
je short ndp_01
mov mNDP,fnone
ret
ndp_01:
mov ax,ndp_cw
cmp ax,03FFH
jne short ndp_02
mov mNDP,f8087
jmp short ndp_04
ndp_02:
.287
cmp ax,037FH
jne short ndp_05
fld1
fldz
fdiv
fld1
fchs
fldz
fdiv
fcom
fstsw ndp_sw
mov ax,ndp_sw
and ah,41H ; C3, C0
cmp ah,40H ; ST(0) = ST(1)
jne short ndp_03
mov mNDP,f80287
jmp short ndp_04
ndp_03:
cmp ah,01H ; ST(0) < ST(1)
jne short ndp_05
mov mNDP,f80387
ndp_04:
.8087
frstor ndp_save
fstcw mNDPCW
ret
ndp_05:
mov mNDP,funk
ret
CPUID endp
;--------------------------------------------------------------------
DISKREAD proc near
assume cs:CODE, ds:DATA, es:nothing
; On entry:
;
; BP
; SP => near return address
; offset of disk buffer
; segment " " "
; number of sectors to read
; starting logical sector number
; drive number (0=A, 1=B, etc.)
;
; On exit:
;
; AX = function result
; 00 - function successful
; 01..FF - DOS INT 25H error result
drive equ [bp + 12]
starting_sector equ [bp + 10]
number_of_sectors equ [bp + 8]
buffer equ [bp + 4]
push bp
mov bp,sp
mov ax,3000h ;get DOS version
int 21h
cmp al,4 ;DOS 4?
jb read3 ;Read assuming DOS 3.x
mov al,drive
mov bx,starting_sector ;copy info into parameter block
mov extd_starting_sector_lo,bx
mov extd_starting_sector_hi,0 ;We're only using lower part
mov bx,number_of_sectors
mov extd_number_of_sectors,bx
les bx,buffer ;get seg:ofs of buffer in ES:BX
mov extd_bufofs,bx ;put into block
mov extd_bufseg,es
mov bx,offset dos4_block ;DS:BX points to block
mov cx,-1 ;-1 means extended read
push ds ;save DS (not really needed, but lets
;me share code with DOS 3 read.)
jmp short readit
read3: mov al,drive
mov dx,starting_sector
mov cx,number_of_sectors
push ds
lds bx,buffer ;get seg:ofs of buffer in DS:BX
readit: int 25H
inc sp ; fix broken stack
inc sp
pop ds
jc short diskread_01
xor ax,ax
diskread_01:
pop bp
ret 10
DISKREAD endp
;
;LONGCALL will call a routine using a CALL FAR. This is used by XMS
;
;Pascal format: procedure longcall(AXi: word; var addr: longint;
; var AXo, BXo, DXo: word); external;
;
longcall proc near
assume cs:CODE, ds:DATA, es:nothing
AXi equ [bp+20] ;set up correct pointers
addr equ [bp+16]
AXo equ [bp+12]
BXo equ [bp+8]
DXo equ [bp+4]
push bp ;setup BP
mov bp,sp
les di,addr ;copy address to call into
mov ax,es:[di] ; local variable
mov word ptr address,ax
mov ax,es:[di+2]
mov word ptr address+2,ax
mov ax,AXi ;get function number
call dword ptr address ;do far call
les di,DXo ;save DX, BX, and AX to correct
mov [es:di],dx ; Pascal variables.
les di,BXo
mov [es:di],bx
les di,AXo
mov [es:di],ax
pop bp ;restore stack
ret 18
longcall endp
;
; ATIINFO is used in the Video identification routine to get special
; information from ATI VGA Wonder cards.
;
; Pascal format: function ATIinfo(data_in: byte, register: word): byte;
;
ATIinfo proc near
assume cs:CODE, ds:DATA, es:NOTHING
data_in equ [bp+6]
register equ [bp+4]
push bp
mov bp,sp
mov dx,register ;get register
mov ax,data_in ;get command word (actually byte)
cli ;no interrupts
out dx,al
inc dx ;next port
in al,dx ;get result
sti ;restore interrupts
mov sp,bp
pop bp
ret 4
ATIinfo endp
code ends
;--------------------------------------------------------------------
DATA segment byte
; storage for CPUID
; redirected INT 01H vector
old_int01 label dword
old_int01_ofs dw ?
old_int01_seg dw ?
; storage for NDPID
; 80x87 control word after initialization, status word after divide by zero
ndp_cw dw ?
ndp_save db 94 dup (?)
ndp_sw dw ?
; storage for DISKREAD
; DOS 4.0 extended read parameter block
dos4_block label byte
extd_starting_sector_lo dw ?
extd_starting_sector_hi dw ?
extd_number_of_sectors dw ?
extd_bufofs dw ?
extd_bufseg dw ?
; storage for LONGCALL
address dd ?
DATA ends
end