home *** CD-ROM | disk | FTP | other *** search
- ; «PL1»
- ;
- ; Assembly routines for BYTE benchmarks
- ; This is the heart of all of the routines.
- ;
-
- ;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
- 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
- ;Clear count
- 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
- MOV CX,SSIZE
- MOV AL,TRUE
- REP STOSB
- ;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
- ;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.
- 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
- 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 CX
- PUSH SI
- PUSH DI
- PUSH DS
- PUSH ES
- ;Load up the registers
- MOV AX,SEG1
- MOV DS,AX
- MOV AX,SEG2
- MOV ES,AX
- MOV SI,OFF1
- MOV DI,OFF2
- MOV CX,NBYTES
- CLD
- REP MOVSB
- ;Restore and return
- POP ES
- POP DS
- POP DI
- POP SI
- POP CX
- 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
- 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 CX
- PUSH SI
- PUSH DI
- PUSH DS
- PUSH ES
- ;Load up the registers
- MOV AX,SEG1
- MOV DS,AX
- MOV AX,SEG2
- MOV ES,AX
- MOV SI,OFF1
- MOV DI,OFF2
- MOV CX,NWORDS
- CLD
- REP MOVSW
- ;Restore and return
- POP ES
- POP DS
- POP DI
- POP SI
- POP CX
- POP BP
- RET
- _do_wmove ENDP
-
- ;****************************
- ; do_dmove *
- ;****************************
- ; do_dmove(seg1,off1,seg1,off2,ndwords
- 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 CX
- PUSH SI
- PUSH DI
- PUSH DS
- PUSH ES
- ;Set up segments
- 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
- ;Restore and return
- POP ES
- POP DS
- POP DI
- POP SI
- POP CX
- POP BP
- RET
- _do_dmove ENDP
-
- ;****************************
- ; do_ifourbang *
- ;****************************
- ; do_ifourbang(ifacseg,numvals)
- 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 SI
- PUSH DS
- ;Load up registers
- 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
- ;Go home
- POP DS
- POP SI
- 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.
- 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
- 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
- ;All done - restore
- 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
- 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
- ; Load up segment registers
- 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
- ;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.
- 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 the segment
- 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
- ;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