1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
|
;****************************************************************************
;*
;* 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
|