home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR2
/
BYTE24.ZIP
/
BENCHSUB.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-04-14
|
52KB
|
2,608 lines
; «PL1»
;
; Assembly routines for BYTE benchmarks
; This is the heart of all of the routines.
;
;
; NOTE: Version 2.4 changes made 4/14/93 by R.G.
; All low-level routines now execute multiple times
; per iteration. These counts MUST be kept in sync with the
; constants set in the C code (BENCHCOD.C).
;General equates
TRUE equ 1
FALSE equ 0
;Equates for timer routine
BIOS_TIME_LO equ 006ch
BIOS_DATASEG equ 0040h
TIMER_MODE equ 43h
TIMER0 equ 40h
MAX_COUNT equ 0ffffh
DOSSEG
.MODEL small
FDATA SEGMENT DWORD PUBLIC
FAC1 DQ 3.0E0
FAC2 DQ 2.0E0
FAC3 DQ 5.050E0
FAC4 DQ 5.050E0
FRESULT DQ ?
FDATA ENDS
.DATA
;Definitions for high-resolution timer.
count_low dw 0 ;number of interrupt tics
count_micro dw 0 ;calc. from interrrupt tics
count_milli dw 0 ;calc. from interrrupt tics
timer_micro dw 0 ;final value
timer_milli dw 0 ; "
timer_sec dw 0 ; "
svd_8253_count dw 0 ;storage space
timer_convert dw 8381 ;838.096 nsec per tick
count_convert dw 54926 ;54.925 mill-sec per count
ten_thousand dw 10000
five_thousand dw 5000
thousand dw 1000
extrn _timeradjust:word ;timer adjustment value
extrn _machine_config: BYTE
coproc equ word ptr _machine_config+6
;Definitions for floating-point
INDEFINITE DD 0FFC00000R ;Indefinite value
IOMEGA DQ ? ;Holds value of i omega
FSTATUS DW ? ;Holds status field
STARTX DQ ? ;For trapezoid
MINUS2 DD -2.0 ;Guess
PIDIV2 DT 1.5707963267948966192 ;pi/2
;Definitions for 8087
CW_87 RECORD RES871:3,INF:1,RND:2,PRECC:2,ERRE:1,RES872:1,PRECM:1,UNFM:1,OVFM:1,ZDM:1,DNM:1,INVM:1
SW_87 RECORD BUSY:1,COND3:1,TOP:3,COND2:1,COND1:1,COND0:1,ERRP:1,RES873:1,PRCE:1,UNFE:1,OVFE:1,ZDE:1,DNE:1,INVE:1
;Definitions for EMS routines
HANDLE1 DW ? ;Storage for first handle
HANDLE2 DW ? ;Storage for second handle
;Configuration stuff for Hercules mode
CRTCP DB 00H,35H ;54 chars horizontal
DB 01,2DH ;45 displayed
DB 02,2EH ;Sync at 46th char
DB 03,07H ;Sync width 7 char clocks
DB 4,5BH ;Vert total of 92 characters
DB 05,02H ;Vert adjust of 2 scan lines
DB 06,57H ;Vert displayed of 87 char rows
DB 07,57H ;Vert. sync after 87th char row
DB 09,03H ;Max scan line, 4 scan lines per char
BDATA DB 7 ;CRT_MODE
DW 80 ;CRT_COLS
DW 8000H ;CRT_LEN
DW 0 ;CRT_START
DW 8 DUP (0) ;CURSOR_POSN
DW 0 ;CURSOR_MODE
DB 0 ;ACTIVE_PAGE
DW 3B4H ;ADDR_6845
CRTMD DB 0AH ;CRT_MODE_SET
DB 0 ;PALLETTE
BDLEN EQU $-BDATA
.CODE
;****************************
; do_sieve *
;****************************
; This routine is called from C with the following
; int do_sieve(flagseg,size);
; flagseg is the segment holding the flags array
; size is the size of the flags array
; The routine returns the number of primes found
;
; 4/14/93 !! This version executes 25 sieves per iteration.--RG
PUBLIC _do_sieve
FLAGSEG equ [BP+4]
SSIZE equ [BP+6]
_do_sieve PROC NEAR
;Save registers
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
;Set loop count -- 4/14/93 RG
MOV CX,25
;Clear count
DS0:
XOR DX,DX
;Set up DS and ES to point to flags segment
MOV AX,FLAGSEG
MOV DS,AX
MOV ES,AX
;Set all flags to true
XOR DI,DI
PUSH CX ;4/14/93 -- RG
MOV CX,SSIZE
MOV AL,TRUE
REP STOSB
POP CX ;4/14/93 -- RG
;Do the main loop
XOR SI,SI ;i=0
DS1: CMP SI,SSIZE ;for(i=0;i<=size;...)
JG DS5
CMP BYTE PTR [SI],TRUE ;if(flags[i])
JNZ DS4A
MOV BX,SI
ADD BX,SI
ADD BX,3 ;prime=i+i+3
;Inner loop
MOV DI,BX
ADD DI,SI ;k=i+prime
DS3: CMP DI,SSIZE ;k<=size
JG DS4
MOV BYTE PTR [DI],FALSE
ADD DI,BX ;k+=prime
JMP DS3
DS4: INC DX ;count++
DS4A: INC SI ;...i++)
JMP DS1
DS5: MOV AX,DX ;Return count
;Do more sieves
LOOP DS0 ;4/14/93 -- RG
;Restore
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP BP
RET
_do_sieve ENDP
;****************************
; do_shell *
;****************************
; This routine performs the shell-sort on an integer array.
; Call with:
; do_shell(arrayseg,top)
; arrayseg is segment address of array to sort
; top is the maximum number of elements in the array
; NOTE: The array to sort MUST begin on a segment boundary.
;
; !!Sort routines have not been changed -- 4/14/93 RG
; They still take enough processor time.
;
PUBLIC _do_shell
SHARRAYSEG equ [BP+4]
SHTOP equ [BP+6]
_do_shell PROC NEAR
;Save registers
PUSH BP
MOV BP,SP
PUSH BX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
;Set up data segment
MOV AX,SHARRAYSEG
MOV DS,AX
;Calculate the gap
MOV BX,SHTOP ;gap=(top-bot)/2
SHR BX,1
;
SHS1: MOV DL,1 ;nex=1
XOR DI,DI ;for(i=0...
SHS2: MOV AX,SHTOP
SUB AX,BX
SHL AX,1 ;Word boundary
CMP DI,AX ;...;i<=top-gap
JG SHS3
MOV SI,DI
ADD SI,BX ;Word boundary
ADD SI,BX
MOV AX,[SI]
CMP AX,[DI]
JGE SHS2A
MOV AX,[SI] ;exchange elements
XCHG AX,[DI]
MOV [SI],AX
XOR DL,DL ;Swap has occurred
SHS2A: INC DI
INC DI ;++i
JMP SHS2
SHS3: OR DL,DL
JZ SHS1
;
SHR BX,1 ;gap=gap/2
JNZ SHS1 ;while(gap!=0)
;Restore
POP DS
POP DI
POP SI
POP DX
POP BX
POP BP
RET
_do_shell ENDP
;****************************
; do_qsort *
;****************************
; This routine performs the quicksort algorithm on an integer array.
; Call with:
; do_qsort(arrayseg,bot,top)
; arrayseg is the segment of the array to sort
; bot is to lowest element in the partition
; top is the highest element in the partition
QSTOP equ [BP+8]
QSBOT equ [BP+6]
QSARRAYSEG equ [BP+4]
PUBLIC _do_qsort
_do_qsort PROC NEAR
;Set up the stack
PUSH BP
MOV BP,SP
PUSH DX
PUSH SI
PUSH DI
PUSH DS
;Point DS register properly
MOV AX,QSARRAYSEG
MOV DS,AX
;while(bot<top)
QS0: MOV AX,QSBOT
CMP AX,QSTOP
JGE QS6
;Set ranges and choose partitioning element
MOV SI,AX ;SI holds i
SHL SI,1 ;Word align
MOV DI,QSTOP ;DI holds j
SHL DI,1 ;Word align
MOV DX,[SI] ;temp=array[bot]
;Partition array
QS1: CMP SI,DI ;while(i<j)
JGE QS5A
QS2: CMP [DI],DX ;while(array[j]>temp)
JLE QS3
DEC DI ;j-=1
DEC DI ;(Word aligned)
JMP QS2
QS3: MOV AX,[DI] ;array[i]=array[j]
MOV [SI],AX
QS4: CMP SI,DI ;while((i<j) && ...
JGE QS5
CMP [SI],DX ;...(array[i]<=temp))
JG QS5
INC SI ;i+=1
INC SI ;(Word aligned)
JMP QS4
QS5: MOV AX,[SI] ;array[j]=array[i]
MOV [DI],AX
JMP QS1
QS5A: MOV [SI],DX ;array[i]=temp
;Call qsort recursively
MOV AX,SI
SHR AX,1 ;Back to non-word alignment
DEC AX
PUSH AX
MOV AX,QSBOT
PUSH AX
PUSH DS
CALL _do_qsort
ADD SP,6 ;Clear stack
SHR SI,1 ;bot=i+1
INC SI
MOV QSBOT,SI
JMP QS0
QS6: POP DS ;Restore
POP DI
POP SI
POP DX
POP BP
RET
_do_qsort ENDP
;****************************
; do_bmove *
;****************************
; Byte-wide move
; Call with:
; do_bmove(seg1,off1,seg2,off2,nbytes)
; seg1,off1 = segment/offset of source
; seg2,off2 = segment/offset of destination
; nbytes = unsigned count of number of bytes to move
;
; !! Each call to this routine performs 25 iterations 4/14/93 RG
;
PUBLIC _do_bmove
_do_bmove PROC NEAR
SEG1 equ [BP+4]
OFF1 equ [BP+6]
SEG2 equ [BP+8]
OFF2 equ [BP+10]
NBYTES equ [BP+12]
;Save everything
PUSH BP
MOV BP,SP
PUSH BX ;4/14/93 RG
PUSH CX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
;Set iteration count
MOV BX,25 ;4/14/93 RG
;Load up the registers
MVB0:
MOV AX,SEG1
MOV DS,AX
MOV AX,SEG2
MOV ES,AX
MOV SI,OFF1
MOV DI,OFF2
MOV CX,NBYTES
CLD
REP MOVSB
;Do more iterations
DEC BX ;4/14/93 RG
JNZ MVB0 ;4/14/93 RG
;Restore and return
POP ES
POP DS
POP DI
POP SI
POP CX
POP BX
POP BP
RET
_do_bmove ENDP
;****************************
; do_wmove *
;****************************
; Word-wide move
; Call with:
; do_bmove(seg1,off1,seg2,off2,nwords)
; seg1,off1 = segment/offset of source
; seg2,off2 = segment/offset of destination
; nwords = unsigned count of number of words to move
; !! Each call to this routine performs 25 iterations 4/14/93 RG
;
PUBLIC _do_wmove
_do_wmove PROC NEAR
SEG1 equ [BP+4]
OFF1 equ [BP+6]
SEG2 equ [BP+8]
OFF2 equ [BP+10]
NWORDS equ [BP+12]
;Save everything
PUSH BP
MOV BP,SP
PUSH BX ;4/14/93 RG
PUSH CX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
;Set iteration count
MOV BX,25 ;4/14/93 RG
;Load up the registers
MVW0:
MOV AX,SEG1
MOV DS,AX
MOV AX,SEG2
MOV ES,AX
MOV SI,OFF1
MOV DI,OFF2
MOV CX,NWORDS
CLD
REP MOVSW
;Do more iterations
DEC BX ;4/14/93 RG
JNZ MVB0 ;4/14/93 RG
;Restore and return
POP ES
POP DS
POP DI
POP SI
POP CX
POP BX ;4/14/93 RG
POP BP
RET
_do_wmove ENDP
;****************************
; do_dmove *
;****************************
; do_dmove(seg1,off1,seg1,off2,ndwords
;
; !! This version performs 25 iteratiosn 4/14/93 RG
PUBLIC _do_dmove
_do_dmove PROC NEAR
SEG1 equ [BP+4]
OFF1 equ [BP+6]
SEG2 equ [BP+8]
OFF2 equ [BP+10]
NDWORDS equ [BP+12]
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
;Set up iteration count
MOV BX,25 ;4/14/93 rg
;Set up segments
MVD0:
MOV AX,SEG1
MOV DS,AX
MOV AX,SEG2
MOV ES,AX
.386
XOR ESI,ESI
XOR EDI,EDI
XOR ECX,ECX
MOV SI,OFF1
MOV DI,OFF2
MOV CX,NDWORDS
CLD
REP MOVSD
.8086
;Do more iterations
DEC BX ;4/14/93 rg
JNZ MVD0 ;4/14/93 rg
;Restore and return
POP ES
POP DS
POP DI
POP SI
POP CX
POP BX
POP BP
RET
_do_dmove ENDP
;****************************
; do_ifourbang *
;****************************
; do_ifourbang(ifacseg,numvals)
;
; !!This version performs 10 iterations 4/14/93 RG
PUBLIC _do_ifourbang
_do_ifourbang PROC NEAR
IFACSEG equ [BP+4]
NUMVALS equ [BP+6]
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX ;4/14/93 RG
PUSH SI
PUSH DS
;Set up loop count
MOV DX,10 ;4/14/93 rg
;Load up registers
IFB0:
PUSH DX ;4/14/93 rg
MOV AX,IFACSEG
MOV DS,AX
MOV CX,NUMVALS
;Start the loop
XOR SI,SI
MOV BX,8
XOR AX,AX
IFB1: ADD AX,[SI]
SUB AX,[SI+2]
IMUL WORD PTR [SI+4]
IDIV WORD PTR [SI+6]
ADD SI,BX
LOOP IFB1
;Do more iterations
POP DX ;4/14/93 rg
DEC DX ;4/14/93 rg
JNZ IFB0 ;4/14/93 rg
;Go home
POP DS
POP SI
POP DX
POP CX
POP BX
POP BP
RET
_do_ifourbang ENDP
.8087
;****************************
; init_fpu *
;****************************
; Initialize FPU
PUBLIC _init_fpu
_init_fpu PROC NEAR
FINIT
RET
_init_fpu ENDP
;****************************
; do_fourbang *
;****************************
; This routine performs the floating-point "four-banger" test.
; Call with:
; do_fourbang(iterations)
; uint iterations
; Where:
; Iterations is the number of times to repeat the loop
PUBLIC _do_fourbang
NFOURBANGS equ [BP+4]
_do_fourbang PROC NEAR
PUSH BP
MOV BP,SP
;See what kind of coprocessor
MOV AX, coproc
PUSH DS ;Swap segment
MOV BX,FDATA
MOV DS,BX
CMP AX,1
JG FNLP ;Do no-waits
ASSUME DS:FDATA
;Initialize the result field
FLDZ
FSTP QWORD PTR FRESULT
;Load loop count
MOV CX,NFOURBANGS
;Do the loops
FLP1:
FLD QWORD PTR FRESULT
FLD QWORD PTR FAC1
FADD
FLD QWORD PTR FAC2
FSUB
FLD QWORD PTR FAC3
FMUL
FLD QWORD PTR FAC4
FDIV
FSTP QWORD PTR FRESULT
LOOP FLP1
;Return
POP DS
POP BP
RET
.387
FNLP:
FLDZ
FSTP QWORD PTR FRESULT
MOV CX,NFOURBANGS
EVEN
FNLP1: FLD QWORD PTR FRESULT
FLD QWORD PTR FAC1
FADD
FLD QWORD PTR FAC2
FSUB
FLD QWORD PTR FAC3
FMUL
FLD QWORD PTR FAC4
FDIV
FSTP QWORD PTR FRESULT
LOOP FNLP1
POP DS
POP BP
RET
_do_fourbang ENDP
.8087
ASSUME DS:_DATA
;****************************
; square_fourier *
;****************************
; Fourier series for a square wave of period 2
; Call with:
; square_fourier(ncoeff,coeffarray)
; ncoeff = number of coefficients
; coeffarray = array of doubles holding results
; NOte that since the period is 2, omega is 2*pi/period = pi.
; Knowing this, we advance the i*omega by simply adding pi
; to that variable on each pass.
; Hey, it works.
;
;!!This version performs 25 iterations.
STEPSIZE equ 501
PUBLIC _square_fourier
NCOEFF equ [BP+4]
COEFFARRAY equ [BP+6]
_square_fourier PROC NEAR
PUSH BP
MOV BP,SP
PUSH SI
PUSH DX ;4/14/93 RG
;Set loop count
MOV DX,25
SQF0:
MOV CX,NCOEFF ;Get # of coefficients
MOV SI,COEFFARRAY ;Pointer to array
;First calculate a0
PUSH CX
MOV CX,STEPSIZE ;Stepsize
MOV BX,OFFSET square_wave
FLD1
FLD1
FADD ;Upper integration limit
FLDZ ;Lover limit
CALL do_trapezoid ;Integrate
FLD1
FLD1
FADD
FDIV ;Result/2 = a0
FSTP QWORD PTR [SI] ;Save a0
ADD SI,4 ;Bump pointer
POP CX
;Set up iw (i omega)
FLDPI
FSTP QWORD PTR IOMEGA
;Calculate remaining a(i) coefficients
SQF1: PUSH CX ;Save loop counter
MOV CX,STEPSIZE ;Stepsize
MOV BX,OFFSET square_cosine
FLD1
FLD1
FADD ;Upper limit
FLDZ ;Lower limit
CALL do_trapezoid
FSTP QWORD PTR [SI] ;Store a(i) coefficient
ADD SI,4 ;Bump pointer
;Calculate remaining b(i) coefficients
MOV CX,STEPSIZE ;Intervals
MOV BX,OFFSET square_sine
FLD1
FLD1
FADD ;Upper limit
FLDZ ;Lower limit
CALL do_trapezoid
FSTP QWORD PTR [SI] ;Store b(i) coefficient
ADD SI,4
;Incremenmt iomega
FLDPI
FADD QWORD PTR IOMEGA
FSTP QWORD PTR IOMEGA
;See if the loop is finished
POP CX
LOOP SQF1
;Do more iterations
DEC DX ;4/14/93 rg
JZ SQFX
JMP SQF0
;All done - restore
SQFX:
POP DX
POP SI
POP BP
RET
_square_fourier ENDP
;****************************
; square_wave *
;****************************
; A square wave of period 2. Valid from x=0.0 to x<2.0
; Wave amplitude is +1/-1
; On entry:
; ST(0)=x
; On exit
; ST(0)=f(x)
square_wave:
FLD1 ;Get a 1.0 on top
FCOM ;See where x is
FSTSW FSTATUS
FWAIT
MOV AX,FSTATUS
AND AH,01000101B ;Get condition bits
FSTP ST(1) ;Discard x
CMP AH,1
JNE SQC2
;x>1 - return a -1
FCHS ;1.0 is now -1.0
SQC2:
RET
;****************************
; square_cosine *
;****************************
; Returns cosine component for fourier series.
; On entry:
; ST(0) = x
; IOMEGA = iw
; On exit:
; ST(0) = f(x) * cos(iwx)
; Where f(x) is a square wave of period 2.
square_cosine:
FLD ST(0) ;Dup x
FMUL QWORD PTR IOMEGA ;iw * x
CALL calc_cosine ;Get cosine of ST(0)
SQC1: FXCH ;Swap
CALL square_wave ;Get f(x) on top
FMUL ;f(x) * cos(iwx)
RET
;****************************
; square_sine *
;****************************
; On entry:
; ST(0) = x
; IOMEGA = iw
; On exit:
; ST(0) = f(x) * sin(iwx)
; Where f(x) is a square wave of period 2.
square_sine:
FLD ST(0) ;Dup x
FMUL QWORD PTR IOMEGA ;iw * x
CALL calc_sine ;sin(iwx)
JMP SQC1 ;Link to common code
;****************************
; do_trapezoid *
;****************************
; On entry:
; CX = number of intervals for integration
; BX = pointer to routine that will push the value of f(x)
; on the FPU stack. x will be stored in ST(0).
; ST(0) = Lower limit of integration
; ST(1) = upper limit of integration
; On exit:
; ST(0) holds value of integration formula
do_trapezoid PROC NEAR
;Save the starting value of x
FST QWORD PTR STARTX
;Calculate the increment width
FSUB ;top - bottom
MOV FSTATUS,CX ;Borrow FSTATUS field
FILD WORD PTR FSTATUS ;Get n (number of intervals)
FDIV ;dx=(top-bottom)/n
;Get f(bottom)
FLD QWORD PTR STARTX
CALL BX ;Call f(x)
FLD1
FADD ST(0),ST ;Calculate 2.0
FDIV ;f(x0)/2
FXCH ST(1) ;-- f(x0)/2 dx
FLD QWORD PTR STARTX ; -- f(x0)/2 dx x
; Stack is now x, dx, f(x0)/2
; Begin the loop
DEC CX
FINTEG1:
FADD ST,ST(1) ;x'=x+dx
FLD ST(0) ;DUP x'
CALL BX ;Get f(x')
FADDP ST(3),ST ;Accumulate and pop f(x)
LOOP FINTEG1
;Calculate f(x)/2 x=endpoint
FADD ST,ST(1)
CALL BX
FLD1
FADD ST(0),ST
FDIV ;Divide by 2
FADDP ST(2),ST ;Accumulate
FMUL ;Times dx
;Return
RET
do_trapezoid ENDP
;****************************
; calc_cosine *
;****************************
; On entry:
; x is stored in ST(0)
; On exit
; cosine(x) is stored in ST(0)
; This routine uses the identities:
; cos(x) = cos(x + pi/2)
; cos(x) = cos(|x|)
calc_cosine:
FLD PIDIV2 ;Load pi/2
FADDP ST(1),ST(0) ;Add to x
FABS ;Take absolute value
CALL calc_sine
RET
;****************************
; calc_sine *
;****************************
; On entry:
; x is stored in ST(0)
; On exit
; sine(x) is stored in ST(0).
; NOTE: This routine is based on the floating-point routines
; found in the public-domain FORTH system ABUNDANCE.
calc_sine:
MOV AX,coproc
CMP AX,3 ;80387?
JNZ CSIN0
JMP SIN387
CSIN0:
PUSH BX
PUSH CX
PUSH DX
XOR DX,DX ;Clear DX
FTST
FSTSW FSTATUS ;Store status word
FWAIT
MOV AX,FSTATUS
SAHF ;Status in flags
JAE CSIN1
MOV DL,0FFH ;Indicate negative
FABS
;Set ST(0) between 0 and pi/4
CSIN1: FLD DWORD PTR MINUS2
FLDPI
FSCALE
FSTP ST(1)
FXCH ST(1)
CSIN2: FPREM
FSTSW FSTATUS
FWAIT
MOV AX,FSTATUS
SAHF
JP CSIN2 ;Jump if C2!=0
FTST
FSTSW FSTATUS
FWAIT
XOR BX,BX
AND FSTATUS,4100H
MOV CX,FSTATUS
CMP CH,40H
JNZ CSIN3
DEC BX ;BX=-1
CSIN3: TEST AH,2
JNZ CSIN5
FSTP ST(1)
OR BX,BX
JZ CSIN4
FSTP ST(0)
FLDZ
FLD1
JMP CSIN7
CSIN4: FPTAN
JMP CSIN7
CSIN5: OR BX,BX
JNZ CSIN6
FSUBP ST(1),ST(0)
FPTAN
JMP CSIN7
CSIN6: FSTP ST(0)
FSTP ST(0)
FLD1
FLD1
CSIN7: XOR BX,BX
TEST AH,40H
JZ CSIN8
INC BX ;BX=1
CSIN8: TEST AH,2
JZ CSIN9
XOR BX,1
JMP CSIN10
CSIN9:
CSIN10: CMP BX,1
JNZ CSIN11
FXCH ST(1)
CSIN11: FMUL ST(0),ST(0)
FLD ST(1)
FMUL ST(0),ST(0)
FADDP ST(1),ST(0)
FSQRT
FDIVP ST(1),ST(0)
TEST AH,1
JZ CSIN12
NOT DL
CSIN12: OR DL,DH
JZ CSIN13
FCHS
CSIN13: POP DX
POP CX
POP BX
RET
.387
;**************************************
; sine387 *
;**************************************
; Sine routine for 80387
sin387: FSIN
; FSTP ST(0)
RET
;**************************************
; GRAPHICS BENCHMARKS *
;**************************************
;**************************************
; random_text *
;**************************************
; Call with:
; random_text(rcseg,attrseg,n,vpage)
; Where:
; rcseg = points to array containing row,col coordinate
; pairs (column in lo byte, row in high)
; attrseg = points to array containing attribute
; bytes
; nbytes = number of entries
; vpage = video page address
;
; !!This version performs 20 iterations
;
PUBLIC _random_text
RTEXTRCSEG equ [BP+4]
RTEXTATTRSEG equ [BP+6]
RTEXTN equ [BP+8]
RTEXTVPAGE equ [BP+10]
_random_text PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
; Set iteration counter
MOV CX,20
; Load up segment registers
RTXT0:
PUSH CX
MOV AX,RTEXTRCSEG
MOV DS,AX
XOR SI,SI
MOV AX,RTEXTATTRSEG
MOV ES,AX
XOR DI,DI
;Set count and video page
MOV CX,RTEXTN
MOV BX,RTEXTVPAGE
MOV BH,BL
;Initialize character
MOV AL,'A'
;Do it
RTXT1: PUSH CX
MOV DX,[SI]
MOV AH,02H
PUSH AX
INT 10H ;Position cursor
POP AX
MOV BL,ES:[DI]
MOV CX,1
MOV AH,09H
INT 10H ;Write the character
INC SI ;Bump pointers
INC SI
INC DI
INC AL
CMP AL,'['
JNZ RTXT2
MOV AL,'A'
RTXT2: POP CX
LOOP RTXT1
;Do outer loops
POP CX
LOOP RTXT0
;Done
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP BP
RET
_random_text ENDP
;****************************
; scroll_text *
;****************************
; Benchmark for text scrolling
; Call with:
; scroll_text(rcaseg,n,vpage)
; Where:
; rcaseg = segment holding array of row/col/attrib coordinates
; n = number of iterations
; vpage = video page
; This benchmark reads the rcseg array 4 elements at a time.
; The first elements holds the row/column coordinates of the
; upper left corner of the rectangle to scroll, while the
; second holds the lower right corner coordinates.
; The third element holds the number of lines to scroll
; The fourth holds attribute bytes used for the background fill
; We assume you've loaded the screen up with stuff before you
; call this routine.
;
; !!This version performs 20 iterations 4/14/93 RG
;
PUBLIC _scroll_text
SCLTXRCASEG equ [BP+4]
SCLTXN equ [BP+6]
SCLTXVPAGE equ [BP+8]
_scroll_text PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DS
;Set up iterations
MOV CX,20
;Set up the segment
STXT0:
PUSH CX
MOV AX,SCLTXRCASEG
MOV DS,AX
XOR SI,SI
;Get iteration count
MOV CX,SCLTXN
;Get video page
MOV BX,SCLTXVPAGE
;Do it
SCLTX1: PUSH CX
;Scroll up
MOV CX,[SI] ;Upper left corner
MOV DX,[SI+2] ;Lowr right corner
MOV AL,[SI+4] ;# of lines
MOV BH,[SI+5] ;Attribute
MOV AH,06H
INT 10H
;Fill up blank area
;**NOTE: I use [SI+4] in the next line instead of AL, because INT 10H,
;function 6 on the Model 80 munges AL. Go figure. --rg
ADD CH,[SI+4] ;Modify ulc
XCHG BH,BL
MOV AL,'A'
CALL FILL_RECT
;Scroll down
XCHG BH,BL
ADD SI,6
MOV CX,[SI] ;Upper left corner
MOV DX,[SI+2] ;Lower right corner
MOV AL,[SI+4] ;# of lines
MOV BH,[SI+5] ;Attribute
MOV AH,07H
INT 10H
;Fill up blank area
SUB DH,[SI+4] ;MOdify lower right corner
XCHG BH,BL
MOV AL,'B'
CALL FILL_RECT
;See if we're done
XCHG BH,BL
ADD SI,6
POP CX
LOOP SCLTX1
;Do outer loops
POP CX
LOOP STXT0
;Go home
POP DS
POP SI
POP DX
POP CX
POP BX
POP BP
RET
_scroll_text ENDP
;Fill_rect
; Called by the scroll routine to fill the blank lines created
; when a window is scrolled.
; On entry:
; CH,CL = row/column of ulhc of rectangle
; DH,CL = row/column of lrhc of rectangle
; AL = character to write
; BL = attribute
; BH = video page
FILL_RECT PROC NEAR
;Calculate number of columns
MOV AH,DL
SUB AH,CL
INC AH
MOV DL,CL
FRECT1: CMP DH,CH
JA FRECT2
RET
FRECT2:
PUSH AX
;Set cursor
MOV AH,2
INT 10H
;Write characters
POP AX
PUSH CX
MOV CL,AH
XOR CH,CH
MOV AH,9
INT 10H
MOV AH,CL
POP CX
;Increment location
DEC DH
JMP FRECT1
FILL_RECT ENDP
;****************************
; draw_circle *
;****************************
; Call with:
; draw_circle (cx,cy,r,color,mode,esseg)
; Where:
; cx,cy are coordinates of center
; r is circle radius in pixels
; color is color
; mode is current graphics mode
; esseg is graphics segment
PUBLIC _draw_circle
DCX equ [BP+4]
DCY equ [BP+6]
DCR equ [BP+8]
DCCOLOR equ [BP+10]
DCMODE equ [BP+12]
DCESSEG equ [BP+14]
_draw_circle PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES
;Set up graphics segment
MOV AX,DCESSEG
MOV ES,AX
;Do initial 4 corners
MOV AX,DCY ;Initial y coord
MOV BX,DCX ;Initial x coord
ADD BX,DCR ;add radius
MOV CX,DCMODE
MOV DX,DCCOLOR
CALL SETPIXEL ;One corner
MOV BX,DCX
SUB BX,DCR
CALL SETPIXEL ;another
MOV BX,DCX
ADD AX,DCR
CALL SETPIXEL ;Another
MOV AX,DCY
SUB AX,DCR
CALL SETPIXEL ;And another
;Do arc from 0 to 45 degrees and reflect
MOV SI,DCR ;x offset
XOR DI,DI ;y offset
MOV DX,DI ;rate of change
DRC1: ADD DX,DI ;dv=dv+y+y+1
ADD DX,DI
INC DX
INC DI ;y+=1
CMP DX,SI ;dv>x?
JLE DRC2
SUB DX,SI ;dv=dv-x-x+1
SUB DX,SI
INC DX
DEC SI ;x-=1
;Now do reflections
DRC2: PUSH DX ;Save rate of change
MOV DX,DCCOLOR ;Reload color
MOV AX,DCY
MOV BX,DCX
ADD BX,SI
ADD AX,DI
CALL SETPIXEL
SUB AX,DI
SUB AX,DI
CALL SETPIXEL
SUB BX,SI
SUB BX,SI
CALL SETPIXEL
ADD AX,DI
ADD AX,DI
CALL SETPIXEL
;If x!=y, do other reflections
CMP SI,DI
JZ DRC3
MOV AX,DCY
MOV BX,DCX
ADD AX,SI
ADD BX,DI
CALL SETPIXEL
SUB AX,SI
SUB AX,SI
CALL SETPIXEL
SUB BX,DI
SUB BX,DI
CALL SETPIXEL
ADD AX,SI
ADD AX,SI
CALL SETPIXEL
;See if done
DRC3: POP DX ;Restore rate of change
CMP DI,SI ;y=x?
JB DRC1
;Go home
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
POP BP
RET
_draw_circle ENDP
;****************************
; do_flood *
;****************************
; Call with:
; do_flood(x,y,color,mode,floodseg,esseg)
; x,y coordinates within bounded region to flood
; color - color to flood with
; mode - graphics mode
; floodseg - use in place of recursive calls; this is
; the pointer to a segment where intermediate
; values will be stored
; esseg - graphics segment
; NOTE: This fellow does NOT check for out-of-screen bounds
; condition. Region MUST be bounded.
PUBLIC _do_flood
DOFLX equ [BP+4]
DOFLY equ [BP+6]
DOFLCOLOR equ [BP+8]
DOFLMODE equ [BP+10]
DOFLSEG equ [BP+12]
DOFLESSEG equ [BP+14]
_do_flood PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DS
PUSH ES
;Set segment for temporaries
MOV AX,DOFLSEG
MOV DS,AX
;Set up graphics segment
MOV AX,DOFLESSEG
MOV ES,AX
XOR SI,SI
;Initialize coordinates and stuff
MOV BX,DOFLX
MOV AX,DOFLY
MOV CX,DOFLMODE
;Set current pixel
DOFL1: MOV DX,DOFLCOLOR
CALL SETPIXEL
;See if pixel above is filled
DEC AX
CALL TESTNPUSH
;See if pixel to right is filled
INC AX
INC BX
CALL TESTNPUSH
;See if pixel below is filled
INC AX
DEC BX
CALL TESTNPUSH
;See if pixel to left is filled
DEC AX
DEC BX
CALL TESTNPUSH
;Anything on pixel stack?
OR SI,SI
JZ DOFL9
;Something there...fetch and loop
SUB SI,4
MOV AX,[SI]
MOV BX,[SI+2]
JMP DOFL1
;Go home
DOFL9:
POP ES
POP DS
POP SI
POP DX
POP CX
POP BX
POP BP
RET
_do_flood ENDP
; TESTNPUSH
; This routine is used by do_flood to see if a pixel should
; be filled. If the pixel qualified, it is "pushed" onto a
; pixel stack pointed to by DS:SI
TESTNPUSH PROC NEAR
PUSH SI ;Save
CALL GETP ;Get pixel's color
POP SI
XOR DH,DH ;Clear hi byte
CMP DX,DOFLCOLOR ;Match?
JZ TNPX ;Already filled if match
MOV [SI],AX ;Push y coordinate
MOV [SI+2],BX ;Push x coordinate
ADD SI,4 ;Increment "stack" pointer
TNPX: RET
TESTNPUSH ENDP
;**************************************
; DISK BENCHMARKS *
;**************************************
;****************************
; rand_cyl_seek *
;****************************
; Random cylinder seek benchmark.
; Call with:
; rand_cyl_seek(arrayseg,size,buffseg,drivenum)
; Where:
; arrayseg = pointer to segment holding array of random
; integers
; size = number of elements in the array
; buffseg = pointer to segment that will be the read buffer
; (In this case, 512 bytes is all you need )
; drivenum = drive number (0=first fixed disk, 1=second)
; NOTE: Elements in arrayseg must already be in cylinder/sector
; format.
PUBLIC _rand_cyl_seek
RCYLARRAYSEG equ [BP+4]
RCYLARRAYSIZE equ [BP+6]
RCYLBUFFSEG equ [BP+8]
RCYLDRIVE equ [BP+10]
_rand_cyl_seek PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH ES
PUSH DS
;Load count
MOV CX,RCYLARRAYSIZE
;Load segment of random numbers and initialize pointer
MOV AX,RCYLARRAYSEG
MOV DS,AX
XOR SI,SI
;Load the buffer segment
MOV AX,RCYLBUFFSEG
MOV ES,AX
XOR BX,BX
;Load drive and head number
MOV DX,RCYLDRIVE
OR DL,80H
XOR DH,DH
;Do it
RCYL1: PUSH CX ;Save loop count
MOV CX,[SI] ;Get cylinder
MOV AH,2
MOV AL,1 ;1 sector
INT 13H
POP CX
JC RCYLE ;Bum out if error
INC SI
INC SI
LOOP RCYL1
XOR AX,AX ;show all ok
RCYLX: POP DS
POP ES
POP SI
POP DX
POP CX
POP BX
POP BP
RET
RCYLE: MOV AL,AH ;Move error to lo byte
XOR AH,AH
JMP RCYLX ;Return with error
_rand_cyl_seek ENDP
;****************************
; hd_rread *
;****************************
; Hard disk random read benchmark.
; This test performs a series of seeks to sector 1 head 0
; for the random cylinder numbers held in arrayseg.
; Call with:
; hd_rread(drive,arrayseg,buffseg,n)
; Where:
; drive = drive number
; arrayseg = segment of array of random cylinder numbers
; nsecseg= number of sectors segment
; buffseg = segment to act as read buffer
; n = number of iterations
; Returns nonzero error code if something happened, else
; returns error.
PUBLIC _hd_rread
HDDRIVE equ [BP+4]
HDARRAYSEG equ [BP+6]
HDBUFFSEG equ [BP+8]
HDN equ [BP+10]
_hd_rread PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DS
PUSH ES
;Load count
MOV CX,HDN
;Load segment of random numbers and initialize pointer
MOV AX,HDARRAYSEG
MOV DS,AX
XOR SI,SI
;Fix buffer pointer
MOV AX,HDBUFFSEG
MOV ES,AX
XOR BX,BX
;Load drive number
MOV DX,HDDRIVE
XOR DH,DH
;Do it
HDRRD1: PUSH CX
MOV CX,[SI]
MOV AX,[SI+2]
MOV AH,2 ;Set code
INT 13H ;Call interrupt
POP CX
; JC HDRRDERR ;Jump if error
ADD SI,4
LOOP HDRRD1
XOR AX,AX ;All ok
;Exit
HDRRDX:
POP ES
POP DS
POP SI
POP DX
POP CX
POP BX
POP BP
RET
; HDRRDERR: MOV AX,CX
; MOV AL,AH ;Error code in AX
; XOR AH,AH
; JMP HDRRDX
_hd_rread ENDP
;***************************
; hd_1seek *
;***************************
; Call with:
; hd_1seek(drive,cyl,bufseg)
; drive = drive to seek on
; cyl = cylinder to seek to (head 0, sector 1)
; bufseg = seg. of buffer to hold 1 sector
;
HD1DRIVE = [BP+4]
HD1CYL = [BP+6]
HD1SEG = [BP+8]
PUBLIC _hd_1seek
_hd_1seek PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH ES
; Set up segments
MOV AX,HD1SEG
MOV ES,AX
; Zero offset
XOR BX,BX
;Set up drive
MOV DX,HD1DRIVE
XOR DH,DH ;Head 0
MOV CX,HD1CYL ;Cylinder
MOV AX,CX
SHR AX,1
SHR AX,1
MOV CH,CL ;Adjust
MOV CL,AH
AND CL,0C0H
INC CL
MOV AL,1
MOV AH,2
INT 13H
JC HD1SERR
HD1SEX: POP ES
POP DX
POP CX
POP BX
POP BP
RET
HD1SERR: MOV AL,AH
XOR AH,AH
JMP HD1SEX
_hd_1seek ENDP
;**************************************
; EMS FUNCTIONS FOLLOW *
;**************************************
;****************************
; do_ems *
;****************************
; Call with:
; do_ems(pfseg,numpages,memseg,width)
; pfseg is the page frame segment address
; numpages is number of EMS pages to allocate per handle
; memseg is pointer to a 16K segment in conventional memory
; width is transfer width -1=byte, 0=word, 1=doubleword
; This fellow runs the following test
; 1. Create two handles, allocating to each numpages EMS
; pages
; 2. Copy contents of memseg into first handle's EMS memory
; 3. Copy contents of memseg into second handle's EMS memory
; 4. Copy entire contents of second handle's EMS memory back
; into first.
; 5. Deallocate pages
;
PUBLIC _do_ems
PFSEG equ [BP+4]
NUMPAGES equ [BP+6]
MEMSEG equ [BP+8]
EMSWIDTH equ [BP+10]
_do_ems PROC NEAR
;Save registers
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES
PUSH DS
;Allocate numpages for handle 1
MOV AH,43H
MOV BX,NUMPAGES
INT 67H
OR AH,AH ;Any errors?
JZ DOEMS1
MOV AL,1 ;Phase in AL
JMP EMSERR
DOEMS1: MOV HANDLE1,DX
;Allocate numpages for handle 2
MOV AH,43H
MOV BX,NUMPAGES
INT 67H
OR AH,AH ;All ok?
JZ DOEMS2
MOV AL,2
JMP EMSERR
DOEMS2: MOV HANDLE2,DX
;Load handle 1 up with information
MOV DX,HANDLE1
CALL LOAD_HANDLE
OR AX,AX
JZ DOEMS3
MOV AL,3 ;Error in phase 3
JMP EMSERR
;Load handle 2 with information
DOEMS3: MOV DX,HANDLE2
CALL LOAD_HANDLE
OR AX,AX
JZ DOEMS4
MOV AL,4 ;Error in phase 4
JMP EMSERR
;Copy handle 2's contents into handle 1
DOEMS4: MOV AX,PFSEG
MOV DS,AX ;Set up source
ADD AX,1024 ;Destination is 2nd page in frame
MOV ES,AX
;
XOR BX,BX
DOEMS5: PUSH BX ;Save number of pages
;Map handle 2's page in
XOR AL,AL ;Physical page 0
MOV AH,44H ;Interrupt
INT 67H
OR AH,AH ;All ok?
JZ DOEMS6
MOV AL,5 ;Error in phase 5
JMP EMSERR
;Map handle 1's page in
DOEMS6:
MOV AL,1 ;Physical page 1
MOV AH,44H ;Interrupt
INT 67H
OR AH,AH ;All ok?
JZ DOEMS7
MOV AL,6 ;Error in phase 6
JMP EMSERR
;Copy stuff
DOEMS7:
CALL COPYPAGE
;See if done
POP BX
INC BX
CMP BX,NUMPAGES
JL DOEMS5
;All done with copy - deallocate
CALL DEALLOC_PAGES
;Show all ok
XOR AX,AX
;Restore registers and exit
EMSXIT:
POP DS
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
POP BP
RET
;Error exit
EMSERR:
XCHG AH,AL
PUSH AX
CALL DEALLOC_PAGES
JMP EMSXIT
_do_ems ENDP
;****************************
; dealloc_pages *
;****************************
DEALLOC_PAGES PROC NEAR
MOV DX,HANDLE1
MOV AH,45H
INT 67H
MOV DX,HANDLE2
MOV AH,45H
INT 67H
RET
DEALLOC_PAGES ENDP
;****************************
; load_handle *
;****************************
; Call with:
; DX = handle number to load
; Returns:
; AX = 0 if ok, else error
LOAD_HANDLE PROC NEAR
;Load up segment registers
MOV AX,MEMSEG
MOV DS,AX ;Memory segment
MOV AX,PFSEG
MOV ES,AX ;Page frame segment
XOR BX,BX ;Start at page 0
LOADHAN1:
PUSH BX
XOR AL,AL ;Physical page 0
MOV AH,44H ;Interrupt
INT 67H
OR AH,AH ;All ok?
JZ LOADHAN2
POP BX ;Clear stack
JMP LOADHANX ;Error exit
;Page now in page frame, copy stuff in
LOADHAN2:
CALL COPYPAGE
;Move to next frame
POP BX
INC BX
CMP BX,NUMPAGES
JL LOADHAN1
XOR AX,AX ;All ok
LOADHANX:
RET
LOAD_HANDLE ENDP
;****************************
; copypage *
;****************************
; Copies one page. It is the caller's responsibility to set
; up the segment registers appropriately
COPYPAGE PROC NEAR
;Set up common stuff
MOV AX,EMSWIDTH ;Copy width?
OR AX,AX
JS COPYBYTE
JZ COPYWORD
;Doubleword copy (386/486 only! )
.386
MOV CX,4096 ;Number of doublewords
XOR ESI,ESI
XOR EDI,EDI
REP MOVSD
RET
.8086
;Word-wide copy
COPYWORD:
MOV CX,8192
XOR SI,SI
XOR DI,DI
REP MOVSW
RET
;Byte-wide copy
COPYBYTE:
MOV CX,16384
XOR SI,SI
XOR DI,DI
REP MOVSB
RET
COPYPAGE ENDP
;
; void start_timer(void)
; call as:
; start_timer()
public _start_timer
_start_timer proc near
push ax
push dx
push ds
;clear the accumulators
mov timer_micro,0
mov timer_milli,0
mov timer_sec,0
;initialize counter 0 of 8253 timer
mov al,00110100b ;ctr 0, lsb then msb,
;...mode 2, binary
out TIMER_MODE,al ;mode register for 8253
sub ax,ax ;0 results in max count
out TIMER0,al ; lsb
out TIMER0,al ; msb
;read current bios time-of-day
mov dx,BIOS_DATASEG
mov ds,dx
mov ax, ds:[BIOS_TIME_LO]
pop ds ;restore my ds
mov count_low,ax
pop dx
pop ax
ret
_start_timer endp
;
; void stop_timer (unsigned int *)
; call:
; stop_timer(tarray)
; where:
; tarray is defined as unsigned int tarray[3]
; tarray[0]=elapsed time, microseconds
; tarray[1]=elapsed time, milliseconds
; tarray[2]=elapsed time, seconds
;
public _stop_timer
_stop_timer proc near
push bp
mov bp,sp
push ax
push bx
push cx
push dx
push di
push si
;read counter 0 of 8253 timer
xor al,al ;latch counter for read
cli ;interrupts off
out TIMER_MODE,al
in al,TIMER0
mov dl,al
in al,TIMER0
mov dh,al ;dx has 16-bit timer count
; we'll defer calculations till after sti
mov svd_8253_count, dx
;get bios time
push ds ;save my data seg
mov dx,BIOS_DATASEG
mov ds,dx
mov ax,ds:[BIOS_TIME_LO]
pop ds
sti ;ints ok now
sub ax,count_low
mul count_convert
cmp dx, 1000
jb no_overflow
; dx is too large, need to pre-divide by 1000
push cx ; use cx as swapping reg
push ax ; save current low word microsecs
mov ax, dx ; move hi word microsecs to dividend
xor dx, dx
div thousand ; now ax = hi word millis, dx = hi w micros
mov cx, ax ; save hi word millis
pop ax ; pop low word microsecs to dividend lo
div thousand
mov count_micro, dx ; save microseconds
mov dx, cx ; now dx=count_milli_hi, ax=count_milli_lo
div thousand ; now ax=count secs, dx=count_milli
mov count_milli, dx
mov timer_sec, ax
pop cx
jmp short gotcount
no_overflow:
div thousand
mov count_milli,ax ;save milliseconds
mov count_micro,dx ;save microseconds
gotcount:
;calc time from 8253
mov dx, svd_8253_count
or ax, MAX_COUNT
sub ax,dx ;timer count value
mul timer_convert ;<10000, so overflow not possible
div ten_thousand ;give time in usec
mov timer_micro,ax ;save usec, round nsec
cmp dx,five_thousand
jb cont
inc timer_micro ;round up
cont:
;restore bios numbers
mov ax, count_milli
mov dx, count_micro
;check for jitter
cmp timer_sec, 0
jne jitter_ok
cmp ax,0
jne jitter_ok
mov ax,_timeradjust
cmp timer_micro,ax
jae jitter_ok
mov timer_micro,ax
;put results in timer variables
jitter_ok:
mov ax,dx ;get count_micro
add ax,timer_micro ;sum micro fields
cmp ax,_timeradjust ;check for underflow
jae compensate
dec count_milli ;borrow
add ax,1000
compensate:
sub ax,_timeradjust ;compensate for timer delays
mov timer_micro,ax
cmp ax,1000 ;check field overflow
jb fld_ok ;timer micro field ok
sub dx,dx ;too large
div thousand ;so carry out into timer_milli
mov timer_milli,ax
mov timer_micro,dx
fld_ok:
mov ax,count_milli ;sum milli field
add timer_milli,ax
cmp timer_milli,1000 ;check as above
jb goback
sub dx,dx
mov ax,timer_milli
div thousand
add timer_sec,ax
mov timer_milli,dx
;send it all back
goback:
push ds
pop es
mov di, [bp+4] ;pointer to array
mov si, offset timer_micro
movsw
movsw
movsw
pop si
pop di
pop dx
pop cx
pop bx
pop ax
pop bp
ret
_stop_timer endp
;****************************
; setp *
;****************************
; Set pixel at x,y to color. Mode is mode #.
; Call with:
; AX = y coordinate of pixel to set
; BX = x coordinate of pixel to set
; CX = mode
; DX = color
; NOTE:
; This routine assumes that ES points to the current video
; page. It is the caller's job to do this.
SETPIXEL PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
;Determine which routine to execute using mode
;First check for Hercules
CMP CL,255
JNE SETPIXEL10
;
; Hercules mode
CALL CALCPH
SETPIXEL01:
SHL DX,CL ;Shift color
NOT DH
AND ES:[BX],DH ;Zero the pixel
OR ES:[BX],DL ;Set it
SETPIXEXIT:
POP DX
POP CX
POP BX
POP AX
RET
;
SETPIXEL10:
CMP CL,6
JGE SETPIXEL20
;
;Modes 4 and 5
;
CALL CALCP4
JMP SHORT SETPIXEL01 ;Borrow code
;
SETPIXEL20:
CMP CL,13
JGE SETPIXEL30
;
;Mode 6
;
CALL CALCP6
JMP SHORT SETPIXEL01 ;Borrow code
;
SETPIXEL30:
CMP CL,14
JGE SETPIXEL40
;
;Mode 13
;
CALL CALCP13
SETPIXEL31:
SHL DH,CL ;Position mask
MOV CX,DX ;Move mask/color to safety
MOV AH,DH
MOV DX,3CEH ;Address register port
MOV AL,8 ;Mask register number
OUT DX,AX
MOV AX,205H ;Mode register number 2, write mode 2
OUT DX,AX
MOV AH,0 ;Replace mode
MOV AL,3 ;Data rotate/function select register
OUT DX,AX
MOV AL,ES:[BX] ;Load the latches
MOV ES:[BX],CL ;Store it
MOV AX,0FF08H ;Restore defaults
OUT DX,AX
MOV AX,5
OUT DX,AX
MOV AX,3
OUT DX,AX
JMP SETPIXEXIT
;
SETPIXEL40:
CMP CL,17
JGE SETPIXEL50
;
; Modes 14,15,16
;
SETPIXEL41:
CALL CALCP14
JMP SHORT SETPIXEL31 ;Borrow code
;
SETPIXEL50:
CMP CL,18
JGE SETPIXEL60
;
; Mode 17
;
CALL CALCP14
JMP SHORT SETPIXEL01 ;Borrow code
;
SETPIXEL60:
CMP CL,18
JZ SETPIXEL41 ;18 same as EGA
;
; Mode 19
;
CALL CALCP19
MOV ES:[BX],DL ;set it
JMP SETPIXEXIT
SETPIXEL ENDP
;****************************
; getp *
;****************************
; Get a pixel's contents.
; Call with:
; AX = y coordinate
; BX = x coordinate
; CX = mode
; Returns:
; DL = color
;
GETP PROC NEAR
PUSH AX
PUSH BX
PUSH CX
CMP CL,255 ;Hercules mode selected by 255
JNE GETP10
;
; Hercules monochrome mode
;
CALL CALCPH
GETP01:
MOV DL,ES:[BX]
SHR DL,CL
AND DL,DH
GETPEXIT: POP CX
POP BX
POP AX
RET
;
GETP10:
CMP CL,6
JGE GETP20
;
; Modes 4 and 5
;
CALL CALCP4
JMP SHORT GETP01 ;Borrow code
;
GETP20:
CMP CL,7
JGE GETP30
;
; Mode 6
;
CALL CALCP6
JMP SHORT GETP01 ;Borrow code
;
GETP30:
CMP CL,14
JGE GETP40
;
; Mode 13
;
CALL CALCP13
GETP31:
MOV CH,DH
SHL CH,CL
MOV SI,BX
MOV DX,3CEH
MOV AX,304H
XOR BL,BL
GETP32:
OUT DX,AX
MOV BH,ES:[SI]
AND BH,CH
NEG BH
ROL BX,1
DEC AH
JGE GETP32
MOV DL,BL
JMP GETPEXIT
;
GETP40:
CMP CL,15
JL GETP51
JNE GETP50
;
; Special for mode 15
;
CALL CALCP14
MOV CH,DH
SHL CH,CL
MOV SI,BX
MOV DX,3CEH
MOV AX,204H
XOR BL,BL
GETP41:
OUT DX,AX
MOV BH,ES:[SI]
AND BH,CH
NEG BH
ROL BX,1
SUB AH,2
JGE GETP41
MOV DL,BL
JMP GETPEXIT
; Mode 17
GETP50:
CMP CL,17
JNZ GETP60
CALL CALCP14
MOV DL,ES:[BX]
SHR DL,CL
AND DL,DH
JMP GETPEXIT
;
; Modes 14 and 16
;
GETP51:
CALL CALCP14
JMP GETP31 ;Borrow code
;
GETP60:
CMP CL,18
JLE GETP51 ;Mode 18 same as EGA 14 and 16
;
; Mode 19
;
CALL CALCP19
MOV DL,ES:[BX]
JMP GETPEXIT
GETP ENDP
;****************************
; ROUTINES FOR CALCULATING A
; PIXEL'S ADDRESS FOLLOW.
;
; Calculate pixel address for modes 4 and 5
; Entry: AX = y coord
; BX = x coord
; Exit: DH = bit mask
; BX = byte offset
; CL = number of bits to shift
CALCP4 PROC NEAR
MOV CL,BL
XCHG AH,AL
SHR AX,1
ADD BH,AL
XOR AL,AL
ADD BX,AX
SHR AX,1
SHR AX,1
ADD BX,AX
SHR BX,1
SHR BX,1
MOV DH,3
AND CL,DH
XOR CL,DH
SHL CL,1
RET
CALCP4 ENDP
;
; Calculate address of pixel for mode 6
; Entry: See abov
; Exit: See above
;
CALCP6 PROC NEAR
MOV CL,BL
XCHG AH,AL
SHR BX,1
SHR AX,1
ADD BH,AL
XOR AL,AL
ADD BX,AX
SHR AX,1
SHR AX,1
ADD BX,AX
SHR BX,1
SHR BX,1
AND CL,7
XOR CL,7
MOV DH,1
RET
CALCP6 ENDP
;
; Calculate pixel address for mode 13
; Entry: See above
; Exit: See above
;
CALCP13:
MOV CL,BL
MOV CH,DL ;Save color and borrow...
MOV DX,40 ;...DX
CP13COM:
MUL DX
SHR BX,1
SHR BX,1
SHR BX,1
ADD BX,AX
AND CL,7
XOR CL,7
MOV DL,CH ;Restore color
MOV DH,1
RET
;
; Calculate pixel address for modes 14,15,16,17,18
; Entry: See above
; Exit: See above
;
CALCP14:
MOV CL,BL
MOV CH,DL ;Save color
MOV DX,80
JMP SHORT CP13COM
;
; Calculate pixel address for mode 19
; Entry: See above
; Exit: See above
; Note: we don't need a bit mask in AH or a shift count in CL
; for this mode.
;
CALCP19 PROC NEAR
XCHG AH,AL
ADD BX,AX
SHR AX,1
SHR AX,1
ADD BX,AX
RET
CALCP19 ENDP
;
; Calculate pixel address for Hercules graphics mode
;
CALCPH PROC NEAR
MOV CL,BL
SHR AX,1
RCR BX,1
SHR AX,1
RCR BX,1
SHR BX,1
MOV AH,90
MUL AH
ADD BX,AX
AND CL,7
XOR CL,7
MOV DH,1
RET
CALCPH ENDP
;****************************
; svmode *
;****************************
; Set video mode. Call with:
;* svmode(mode) int mode;
; Set video mode.
; Mode is:
; 0 - 40 x 25 chars b&w (cga,ega,mcga,vga)
; 1 - 40 x 25 chars color (cga,ega,mcga,vga)
; 2 - 80 x 25 chars b&w (cga,ega,mcga,vga)
; 3 - 80 x 25 chars color (cga,ega,mcga,vga)
; 4 - 320 x 200 4-color graph (cga,ega,mcga,vga)
; 5 - 320 x 200 b&w graph (cga,ega,mcga,vga)
; 6 - 640 x 200 b&w graph (cga,ega,mcga,vga)
; 7 - 80 x 25 chars b&w (mda,ega,vga)
; 8 - 160 x 200 16-color graph (jr)
; 9 - 320 x 200 16-color graph (jr)
; 10 - 640 x 200 4-color graph (jr)
; 11 - reserved by EGA video BIOS
; 12 - reserved by EGA video BIOS
; 13 - 320 x 200 16-color graph (ega,vga)
; 14 - 640 x 200 16-color graph (ega,vga)
; 15 - 640 x 350 2-color graph (ega,vga)
; 16 - 640 x 350 4- or 16-color (ega,vga)
; 17 - 640 x 480 2-color (mcga,vga)
; 18 - 640 x 480 16-color (vga)
; 19 - 320 x 200 256-color (mcga,vga)
; 255 - Heculese 720x348 monochrome graphics
PUBLIC _svmode
_svmode PROC NEAR
PUSH BP
MOV BP,SP
PUSH SI
PUSH DI
MOV AX,4[BP]
CMP AX,255 ;Hercules?
JZ HERC
PUSH DS
MOV BX,40H ;Video display data area
MOV DS,BX
MOV BL,32 ;Presence of CGA
MOV AX,4[BP]
MOV DL,AL
AND DL,7
CMP DL,7
JNE SVM1
MOV BL,48 ;Presence of MDA
SVM1: AND BYTE PTR DS:[10H],11001111B
OR BYTE PTR DS:[10H],BL
INT 10H ;Set the mode
POP DS ;Restore DS
POP DI
POP SI
POP BP
RET
HERC:
;Update video bios data area
PUSH ES
MOV AX,40H
MOV ES,AX
MOV DI,49H ;ES:DI is video bios data area
MOV SI,OFFSET BDATA
MOV CX,BDLEN
REP MOVSB ;Update video bios data
;Set config. switch
MOV DX,3BFH ;Config switch port
MOV AL,1 ;Exclude second 32K of video buffer
OUT DX,AL
;Blank the screen
MOV DX,3B8H
XOR AL,AL
OUT DX,AL
;Program the CRTC
SUB DL,4 ;3b4H is addres reg port of CRTC
MOV SI,OFFSET CRTCP
MOV CX,9 ;9 parameters to load
HERC1: LODSW ;Al=crtc register number/AH=VALUE
OUT DX,AX
LOOP HERC1
;Set graphics mode
ADD DL,4
MOV AL,CRTMD
OUT DX,AL
;Clear the video buffer
MOV AX,0B000H
MOV ES,AX
XOR AX,AX ;Clear to zero
XOR DI,DI
MOV CX,4000H
REP STOSW
POP ES
POP DI
POP SI
POP BP
RET ;Go home
_svmode ENDP
;****************************
; gvmode *
;****************************
; Get video mode. Returns current video mode number.
PUBLIC _gvmode
_gvmode PROC NEAR
MOV AH,0FH
INT 10H
XOR AH,AH ;Clear hi part of mode number
RET
_gvmode ENDP
;*****************************
; FILE IO ROUTINES *
;*****************************
;
;*****************************
; ll_open *
;*****************************
; Open a file with read/write access.
; Call with:
; hand=ll_open(nameptr)
; Where:
; nameptr = pointer to file's name (null-terminated)
; Returns handle. If handle<0, indicates error.
PUBLIC _ll_open
OPENNAMEPTR equ [BP+4]
_ll_open PROC NEAR
PUSH BP
MOV BP,SP
PUSH DX
;Issue the call
MOV DX,OPENNAMEPTR
MOV AH,3DH
MOV AL,2 ;Read/write
INT 21H
JC LLOPZ
;Return handle
LLOPX:
POP DX
POP BP
RET
LLOPZ: NEG AX
JMP LLOPX
_ll_open ENDP
;*****************************
; ll_close *
;*****************************
; Close a file.
; Call with:
; ll_close(handle)
; Where:
; handle = file's handle.
PUBLIC _ll_close
CLOSEHAND equ [BP+4]
_ll_close PROC NEAR
PUSH BP
MOV BP,SP
;Get the handle
MOV BX,CLOSEHAND
MOV AH,3EH
INT 21H
POP BP
RET
_ll_close ENDP
;*****************************
; ll_create *
;*****************************
; Create a file with read/write access.
; Call with:
; hand=ll_create(nameptr)
; Where:
; nameptr = pointer to file's name (null-terminated)
; Returns handle. If handle<0, indicates error.
PUBLIC _ll_create
CREATNAMEPTR equ [BP+4]
_ll_create PROC NEAR
PUSH BP
MOV BP,SP
;Get the file name and create it.
MOV DX,CREATNAMEPTR
MOV AH,3CH
XOR CX,CX
INT 21H
JC LLCRZ
;Return handle
LLCRX: POP BP
RET
;Return error
LLCRZ: NEG AX
JMP LLCRX
_ll_create ENDP
;*****************************
; ll_seekread *
;*****************************
; Seek-and-read an open file.
; Call with:
; result=ll_seekread(handle,offset,mode,buffer,nbytes)
; Where:
; handle = handle of file to read
; offset = byte offset
; mode = offset mode
; buffer = segment of buffer to read into
; nbytes = number of bytes to read
; Returns:
; Number of bytes actually read. If error, result is negative
; and contains error code.
; Note: The data is read into the segment starting at offset 0.
PUBLIC _ll_seekread
SRHANDLE equ [BP+4]
SROFFSETL equ [BP+6]
SROFFSETH equ [BP+8]
SRMODE equ [BP+10]
SRBUFFSEG equ [BP+12]
SRNBYTES equ [BP+14]
_ll_seekread PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH DS
;Do the seek first
MOV BX,SRHANDLE ;Get handle
MOV DX,SROFFSETL ;Get byte offset
MOV CX,SROFFSETH
MOV AX,SRMODE
MOV AH,42H
INT 21H ;Do the seek
JC SRERR ;Error if carry set
;Now do the read
MOV AX,SRBUFFSEG
MOV DS,AX
XOR DX,DX ;Set address
MOV CX,SRNBYTES ;Number of bytes
MOV AH,3FH
INT 21H ;Do the read
JC SRERR
;Return bytes actually read
SRX:
POP DS
POP DX
POP CX
POP BX
POP BP
RET
;Return error code
SRERR: NEG AX
JMP SRX
_ll_seekread ENDP
;*****************************
; ll_seekwrite *
;*****************************
; Seek-and-write an open file.
; Call with:
; result=ll_seekwrite(handle,offset,mode,buffer,nbytes)
; Where:
; handle = handle of file to write
; offset = byte offset
; mode = seek mode
; buffer = segment of buffer to write from
; nbytes = number of bytes to write
; Returns:
; Number of bytes actually written. If error, result is negative
; and contains error code.
; Note: The data is written from the segment starting at offset 0.
PUBLIC _ll_seekwrite
SWHANDLE equ [BP+4]
SWOFFSETL equ [BP+6]
SWOFFSETH equ [BP+8]
SWMODE equ [BP+10]
SWBUFFSEG equ [BP+12]
SWNBYTES equ [BP+14]
_ll_seekwrite PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH DS
;Do the seek first
MOV BX,SWHANDLE ;Get handle
MOV DX,SWOFFSETL ;Get byte offset
MOV CX,SWOFFSETH
MOV AX,SWMODE ;Seek mode
MOV AH,42H
INT 21H ;Do the seek
JC SWERR ;Error if carry set
;Now do the write
MOV AX,SWBUFFSEG
MOV DS,AX
XOR DX,DX ;Set address
MOV CX,SWNBYTES ;Number of bytes
MOV AH,40H
INT 21H ;Do the write
JC SWERR
;Return bytes actually write
SWX:
POP DS
POP DX
POP CX
POP BX
POP BP
RET
;Return error code
SWERR: NEG AX
JMP SWX
_ll_seekwrite ENDP
;****************************
; ll_filelen *
;****************************
; Return a file's length.
; ulong = ll_filelen(fh)
PUBLIC _ll_filelen
FLENFH equ [BP+4] ;File handle
_ll_filelen PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
;First do a seek on the file
MOV BX,FLENFH ;Get handle
XOR CX,CX
XOR DX,DX ;Offset 0
MOV AL,2 ;End of file
MOV AH,42H
INT 21H
;Return the offset
POP DX
POP CX
POP BX
POP BP
RET
_ll_filelen ENDP
END