249 lines
8.4 KiB
NASM
249 lines
8.4 KiB
NASM
;****************************************************************************
|
|
;*
|
|
;* SciTech Nucleus Graphics Architecture
|
|
;*
|
|
;* Copyright (C) 1991-1998 SciTech Software, Inc.
|
|
;* All rights reserved.
|
|
;*
|
|
;* ======================================================================
|
|
;* |REMOVAL OR MODIFICATION OF THIS HEADER IS STRICTLY PROHIBITED BY LAW|
|
|
;* | |
|
|
;* |This copyrighted computer code contains proprietary technology |
|
|
;* |owned by SciTech Software, Inc., located at 505 Wall Street, |
|
|
;* |Chico, CA 95928 USA (http://www.scitechsoft.com). |
|
|
;* | |
|
|
;* |The contents of this file are subject to the SciTech Nucleus |
|
|
;* |License; you may *not* use this file or related software except in |
|
|
;* |compliance with the License. You may obtain a copy of the License |
|
|
;* |at http://www.scitechsoft.com/nucleus-license.txt |
|
|
;* | |
|
|
;* |Software distributed under the License is distributed on an |
|
|
;* |"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
|
|
;* |implied. See the License for the specific language governing |
|
|
;* |rights and limitations under the License. |
|
|
;* | |
|
|
;* |REMOVAL OR MODIFICATION OF THIS HEADER IS STRICTLY PROHIBITED BY LAW|
|
|
;* ======================================================================
|
|
;*
|
|
;* Language: 80386 Assembler, NASM or TASM
|
|
;* Environment: IBM PC 32 bit Protected Mode.
|
|
;*
|
|
;* Description: Assembly support functions for the Nucleus library for
|
|
;* the high resolution timing support functions provided by
|
|
;* the Intel Pentium and compatible processors.
|
|
;*
|
|
;****************************************************************************
|
|
|
|
IDEAL
|
|
|
|
include "scitech.mac" ; Memory model macros
|
|
|
|
header _gatimer
|
|
|
|
begcodeseg _gatimer
|
|
|
|
ifdef USE_NASM
|
|
%macro mCPU_ID 0
|
|
db 00Fh,0A2h
|
|
%endmacro
|
|
else
|
|
MACRO mCPU_ID
|
|
db 00Fh,0A2h
|
|
ENDM
|
|
endif
|
|
|
|
ifdef USE_NASM
|
|
%macro mRDTSC 0
|
|
db 00Fh,031h
|
|
%endmacro
|
|
else
|
|
MACRO mRDTSC
|
|
db 00Fh,031h
|
|
ENDM
|
|
endif
|
|
|
|
;----------------------------------------------------------------------------
|
|
; bool _GA_haveCPUID(void)
|
|
;----------------------------------------------------------------------------
|
|
; Determines if we have support for the CPUID instruction.
|
|
;----------------------------------------------------------------------------
|
|
cprocstart _GA_haveCPUID
|
|
|
|
enter_c
|
|
pushfd ; Get original EFLAGS
|
|
pop eax
|
|
mov ecx, eax
|
|
xor eax, 200000h ; Flip ID bit in EFLAGS
|
|
push eax ; Save new EFLAGS value on stack
|
|
popfd ; Replace current EFLAGS value
|
|
pushfd ; Get new EFLAGS
|
|
pop eax ; Store new EFLAGS in EAX
|
|
xor eax, ecx ; Can not toggle ID bit,
|
|
jnz @@1 ; Processor=80486
|
|
mov eax,0 ; We dont have CPUID support
|
|
jmp @@Done
|
|
@@1: mov eax,1 ; We have CPUID support
|
|
@@Done: leave_c
|
|
ret
|
|
|
|
cprocend
|
|
|
|
;----------------------------------------------------------------------------
|
|
; uint _GA_getCPUIDFeatures(void)
|
|
;----------------------------------------------------------------------------
|
|
; Determines the CPU type using the CPUID instruction.
|
|
;----------------------------------------------------------------------------
|
|
cprocstart _GA_getCPUIDFeatures
|
|
|
|
enter_c
|
|
|
|
xor eax, eax ; Set up for CPUID instruction
|
|
mCPU_ID ; Get and save vendor ID
|
|
cmp eax, 1 ; Make sure 1 is valid input for CPUID
|
|
jl @@Fail ; We dont have the CPUID instruction
|
|
xor eax, eax
|
|
inc eax
|
|
mCPU_ID ; Get family/model/stepping/features
|
|
mov eax, edx
|
|
@@Done: leave_c
|
|
ret
|
|
|
|
@@Fail: xor eax,eax
|
|
jmp @@Done
|
|
|
|
cprocend
|
|
|
|
;----------------------------------------------------------------------------
|
|
; void _GA_readTimeStamp(GA_largeInteger *time)
|
|
;----------------------------------------------------------------------------
|
|
; Reads the time stamp counter and returns the 64-bit result.
|
|
;----------------------------------------------------------------------------
|
|
cprocstart _GA_readTimeStamp
|
|
|
|
mRDTSC
|
|
mov ecx,[esp+4] ; Access directly without stack frame
|
|
mov [ecx],eax
|
|
mov [ecx+4],edx
|
|
ret
|
|
|
|
cprocend
|
|
|
|
;----------------------------------------------------------------------------
|
|
; N_uint32 GA_TimerDifference(GA_largeInteger *a,GA_largeInteger *b)
|
|
;----------------------------------------------------------------------------
|
|
; Computes the difference between two 64-bit numbers (a-b)
|
|
;----------------------------------------------------------------------------
|
|
cprocstart GA_TimerDifference
|
|
|
|
ARG a:DPTR, b:DPTR, t:DPTR
|
|
|
|
enter_c
|
|
|
|
mov ecx,[a]
|
|
mov eax,[ecx] ; EAX := b.low
|
|
mov ecx,[b]
|
|
sub eax,[ecx]
|
|
mov edx,eax ; EDX := low difference
|
|
mov ecx,[a]
|
|
mov eax,[ecx+4] ; ECX := b.high
|
|
mov ecx,[b]
|
|
sbb eax,[ecx+4] ; EAX := high difference
|
|
mov eax,edx ; Return low part
|
|
|
|
leave_c
|
|
ret
|
|
|
|
cprocend
|
|
|
|
; Macro to delay briefly to ensure that enough time has elapsed between
|
|
; successive I/O accesses so that the device being accessed can respond
|
|
; to both accesses even on a very fast PC.
|
|
|
|
ifdef USE_NASM
|
|
%macro DELAY_TIMER 0
|
|
jmp short $+2
|
|
jmp short $+2
|
|
jmp short $+2
|
|
%endmacro
|
|
else
|
|
macro DELAY_TIMER
|
|
jmp short $+2
|
|
jmp short $+2
|
|
jmp short $+2
|
|
endm
|
|
endif
|
|
|
|
;----------------------------------------------------------------------------
|
|
; void _OS_delay8253(N_uint32 microSeconds);
|
|
;----------------------------------------------------------------------------
|
|
; Delays for the specified number of microseconds, by directly programming
|
|
; the 8253 timer chips.
|
|
;----------------------------------------------------------------------------
|
|
cprocstart _OS_delay8253
|
|
|
|
ARG microSec:UINT
|
|
|
|
enter_c
|
|
|
|
; Start timer 2 counting
|
|
|
|
mov _ax,[microSec] ; EAX := count in microseconds
|
|
mov ecx,1196
|
|
mul ecx
|
|
mov ecx,1000
|
|
div ecx
|
|
mov ecx,eax ; ECX := count in timer ticks
|
|
in al,61h
|
|
or al,1
|
|
out 61h,al
|
|
|
|
; Set the timer 2 count to 0 again to start the timing interval.
|
|
|
|
mov al,10110100b ; set up to load initial (timer 2)
|
|
out 43h,al ; timer count
|
|
DELAY_TIMER
|
|
sub al,al
|
|
out 42h,al ; load count lsb
|
|
DELAY_TIMER
|
|
out 42h,al ; load count msb
|
|
xor di,di ; Allow max 64K loop iterations
|
|
|
|
@@LoopStart:
|
|
dec di ; This is a guard against the possibility that
|
|
jz @@LoopEnd ; someone eg. stopped the timer behind our back.
|
|
; After 64K iterations we bail out no matter what
|
|
; (and hope it wasn't too soon)
|
|
mov al,00000000b ; latch timer 0
|
|
out 43h,al
|
|
DELAY_TIMER
|
|
in al,42h ; least significant byte
|
|
DELAY_TIMER
|
|
mov ah,al
|
|
in al,42h ; most significant byte
|
|
xchg ah,al
|
|
neg ax ; Convert from countdown remaining
|
|
; to elapsed count
|
|
cmp ax,cx ; Has delay expired?
|
|
jb @@LoopStart ; No, so loop till done
|
|
|
|
; Stop timer 2 from counting
|
|
@@LoopEnd:
|
|
in al,61H
|
|
and al,0FEh
|
|
out 61H,al
|
|
|
|
; Some programs have a problem if we change the control port; better change it
|
|
; to something they expect (mode 3 - square wave generator)...
|
|
mov al,0B6h
|
|
out 43h,al
|
|
|
|
leave_c
|
|
ret
|
|
|
|
cprocend
|
|
|
|
endcodeseg _gatimer
|
|
|
|
END
|
|
|