                NAME    TIME

_TEXT   SEGMENT  WORD PUBLIC 'CODE'
_TEXT   ENDS
CONST   SEGMENT  WORD PUBLIC 'CONST'
CONST   ENDS
_BSS    SEGMENT  WORD PUBLIC 'BSS'
_BSS    ENDS
_DATA   SEGMENT  WORD PUBLIC 'DATA'
_DATA   ENDS
DGROUP  GROUP   CONST,  _BSS,   _DATA
        ASSUME  CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP

TESTSEG SEGMENT WORD PUBLIC 'TEST'

TESTSEG_START   DW      32767 DUP (?)

TESTSEG ENDS

PPI_PORT        EQU     061H
TIMER2_PORT     EQU     042H
TIMER_CTRL      EQU     043H

_DATA           SEGMENT

VIDBASE         DW      0B800H
EMMBASE         DW      9000H
PID             DW      ?
EMM_NAME        DB      "EMMXXXX0"

_DATA           ENDS

_TEXT           SEGMENT

;***************************************************************;
;                                                               ;
;       _MULTIME                                                ;
;                                                               ;
;       TIME EXECUTION OF MULTIPLY INSTRUCTIONS                 ;
;                                                               ;
;***************************************************************;

        EVEN
                PUBLIC  _MULTIME
_MULTIME        PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, 0                   ; CLEAR DI
        MOV     AX, [BP+4]              ; GET COUNT ARGUMENT
        ADD     AX, 99                  ; ROUND UP
        MOV     CX, 100                 ; DIVIDE BY 100 =
        DIV     CL                      ;  NUMBER OF INSTRUCTIONS
        MOV     CL, AL                  ;  PER PASS
        NOP                             ; ALIGN INSTRUCTIONS
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        OUT     PPI_PORT, AL            ; ENABLE TIMER
ML:     MUL     DI                      ; DO 100 MULTIPLIES
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        MUL     DI                      ;
        DEC     CX                      ; COUNT THIS PASS
        JZ      MD                      ; JUMP IF COMPLETE
        JMP     ML                      ; LOOP BACK IF NOT DONE
MD:     MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_MULTIME        ENDP

;***************************************************************;
;                                                               ;
;       _WMOVTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF MOV INSTRUCTION (INSTR. READ TIME)    ;
;                                                               ;
;***************************************************************;

        EVEN
                PUBLIC  _WMOVTIME
_WMOVTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, 0                   ; CLEAR DI
        MOV     AX, [BP+4]              ; GET COUNT ARGUMENT
        ADD     AX, 99                  ; ROUND UP
        MOV     CX, 100                 ; DIVIDE BY 100 =
        DIV     CL                      ;  NUMBER OF INSTRUCTIONS
        MOV     CL, AL                  ;  PER PASS
        NOP                             ; ALIGN INSTRUCTIONS
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        OUT     PPI_PORT, AL            ; ENABLE TIMER
IL:     MOV     DX, BX                  ; DO 100 MULTIPLIES
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        MOV     DX, BX                  ;
        DEC     CX                      ; COUNT THIS PASS
        JZ      ID                      ; JUMP IF COMPLETE
        JMP     IL                      ; LOOP BACK IF NOT DONE
ID:     MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_WMOVTIME       ENDP

;***************************************************************;
;                                                               ;
;       _BMVSTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP MOVSB INSTRUCTION                 ;
;                                                               ;
;***************************************************************;

                PUBLIC  _BMVSTIME
_BMVSTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DS                      ; SAVE DS
        PUSH    ES                      ; SAVE ES
        PUSH    SI                      ; SAVE SI
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, TESTSEG             ;
        MOV     ES, DI                  ;
        MOV     DS, DI                  ;
        LEA     SI, TESTSEG_START       ; DS:SI -> TEST SEGMENT
        LEA     DI, TESTSEG_START       ; ES:DI -> TEST SEGMENT
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP MOVSB                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     SI                      ; RESTORE SI
        POP     ES                      ; RESTORE ES
        POP     DS                      ; RESTORE DS
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_BMVSTIME       ENDP

;***************************************************************;
;                                                               ;
;       _WMVSTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP MOVSW INSTRUCTION                 ;
;                                                               ;
;***************************************************************;

                PUBLIC  _WMVSTIME
_WMVSTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DS                      ; SAVE DS
        PUSH    ES                      ; SAVE ES
        PUSH    SI                      ; SAVE SI
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, TESTSEG             ;
        MOV     ES, DI                  ;
        MOV     DS, DI                  ;
        LEA     SI, TESTSEG_START       ; DS:SI -> TEST SEGMENT
        LEA     DI, TESTSEG_START       ; ES:DI -> TEST SEGMENT
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP MOVSW                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     SI                      ; RESTORE SI
        POP     ES                      ; RESTORE ES
        POP     DS                      ; RESTORE DS
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_WMVSTIME       ENDP

;***************************************************************;
;                                                               ;
;       _WPSHTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF PUSHA INSTRUCTION                     ;
;                                                               ;
;***************************************************************;

        EVEN
                PUBLIC  _WPSHTIME
_WPSHTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     AX, [BP+4]              ; GET COUNT ARGUMENT
        CWD                             ; MAKE DOUBLE WORD
        MOV     CX, 200                 ;
        DIV     CX                      ; DIVIDE BY MOVS/LOOP
        MOV     CX, AX                  ;
        NOP                             ; ALIGN INSTRUCTIONS
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        OUT     PPI_PORT, AL            ; ENABLE TIMER
WSL:    DB      60H                     ; PUSH THE REGISTERS
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        MOV     SP, BP                  ; PUT THE STACK BACK
        LOOP    WSL                     ; LOOP UNTIL DONE
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        MOV     SP, BP                  ; PUT THE STACK BACK
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_WPSHTIME       ENDP

;***************************************************************;
;                                                               ;
;       _BROMTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP MOVSB INSTRUCTION FROM ROM        ;
;                                                               ;
;***************************************************************;

                PUBLIC  _BROMTIME
_BROMTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DS                      ; SAVE DS
        PUSH    ES                      ; SAVE ES
        PUSH    SI                      ; SAVE SI
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, TESTSEG             ;
        MOV     ES, DI                  ;
        MOV     DI, 0F000H              ; SET DS TO ROM START
        MOV     DS, DI                  ;
        MOV     SI, 0                   ; DS:SI -> ROM
        LEA     DI, TESTSEG_START       ; ES:DI -> TEST SEGMENT
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP MOVSB                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     SI                      ; RESTORE SI
        POP     ES                      ; RESTORE ES
        POP     DS                      ; RESTORE DS
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_BROMTIME       ENDP

;***************************************************************;
;                                                               ;
;       _WROMTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP MOVSW INSTRUCTION FROM ROM        ;
;                                                               ;
;***************************************************************;

                PUBLIC  _WROMTIME
_WROMTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DS                      ; SAVE DS
        PUSH    ES                      ; SAVE ES
        PUSH    SI                      ; SAVE SI
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, TESTSEG             ;
        MOV     ES, DI                  ;
        MOV     DI, 0F000H              ; SET DS TO ROM START
        MOV     DS, DI                  ;
        MOV     SI, 0                   ; DS:SI -> ROM
        LEA     DI, TESTSEG_START       ; ES:DI -> TEST SEGMENT
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP MOVSW                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     SI                      ; RESTORE SI
        POP     ES                      ; RESTORE ES
        POP     DS                      ; RESTORE DS
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_WROMTIME       ENDP

;***************************************************************;
;                                                               ;
;       _BVIDTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP STOSB INTO VIDEO MEMORY           ;
;                                                               ;
;***************************************************************;

                PUBLIC  _BVIDTIME
_BVIDTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    ES                      ; SAVE ES
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, VIDBASE             ; GET BASE ADDRESS
        MOV     ES, DI                  ;
        MOV     DI, 0                   ; ES:DI -> VIDEO MEMORY
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP STOSB                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     ES                      ; RESTORE ES
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_BVIDTIME       ENDP

;***************************************************************;
;                                                               ;
;       _WVIDTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP STOSW INTO VIDEO MEMORY           ;
;                                                               ;
;***************************************************************;

                PUBLIC  _WVIDTIME
_WVIDTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    ES                      ; SAVE ES
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, VIDBASE             ; GET BASE ADDRESS
        MOV     ES, DI                  ;
        MOV     DI, 0                   ; ES:DI -> VIDEO MEMORY
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP STOSW                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     ES                      ; RESTORE ES
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_WVIDTIME       ENDP

;***************************************************************;
;                                                               ;
;       _SETUP_VIDEO                                            ;
;                                                               ;
;       DETECT THE TYPE OF VIDEO CARD AND SAVE THE BASE         ;
;                                                               ;
;***************************************************************;

                PUBLIC  _SETUP_VIDEO
_SETUP_VIDEO    PROC    NEAR

        PUSH    BP                      ; SAVE REGISTERS
        PUSH    ES                      ;
        PUSH    SI                      ;
        PUSH    DI                      ;
        INT     11H                     ; EQUIPMENT DETERMINATION
        AND     AL, 30H                 ; MASK DISPLAY BITS
        CMP     AL, 30H                 ; CHECK FOR MONOCHROME
        MOV     AX, 0B000H              ; MONOCHROME BASE
        JE      SVM                     ; JUMP IF MONOCHROME
        MOV     AX, 0B800H              ; COLOR BASE
SVM:    MOV     VIDBASE, AX             ; SAVE BASE ADDRESS
        POP     DI                      ; RESTORE REGISTERS
        POP     SI                      ;
        POP     ES                      ;
        POP     BP                      ;
        RET                             ; RETURN 0

_SETUP_VIDEO    ENDP

;***************************************************************;
;                                                               ;
;       _FPTIME                                                 ;
;                                                               ;
;       TIME EXECUTION OF FLOATING POINT DIVIDE                 ;
;                                                               ;
;***************************************************************;

                PUBLIC  _FPTIME
_FPTIME         PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, 0                   ; CLEAR DI
        MOV     AX, [BP+4]              ; GET COUNT ARGUMENT
        ADD     AX, 99                  ; ROUND UP
        MOV     CX, 100                 ; DIVIDE BY 100 =
        DIV     CL                      ;  NUMBER OF INSTRUCTIONS
        MOV     CL, AL                  ;  PER PASS
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        FNINIT                          ; INIT FP
        FLD1                            ; DIVIDE 1.0
        FLD1                            ; BY 1.0
        CLI                             ; STOP INTERRUPTS
        OUT     PPI_PORT, AL            ; ENABLE TIMER
FL:     FDIV    ST(1), ST               ; DO 100 DIVIDES
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        FDIV    ST(1), ST               ;
        DEC     CX                      ; COUNT THIS PASS
        JZ      FD                      ; JUMP IF COMPLETE
        JMP     FL                      ; LOOP BACK IF NOT DONE
FD:     MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_FPTIME        ENDP

;***************************************************************;
;                                                               ;
;       _WEMPTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF PUSHA INSTRUCTION                     ;
;                                                               ;
;***************************************************************;

        EVEN
                PUBLIC  _WEMPTIME
_WEMPTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        PUSH    DI                      ; SAVE DI
        MOV     BP, SP                  ;
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     AX, [BP+6]              ; GET COUNT ARGUMENT
        CWD                             ; MAKE DOUBLE WORD
        MOV     CX, 200                 ;
        DIV     CX                      ; DIVIDE BY MOVS/LOOP
        MOV     CX, AX                  ;
        NOP                             ; ALIGN INSTRUCTIONS
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        MOV     DX, SS                  ; SAVE STACK SEGMENT
        MOV     SS, EMMBASE             ; PUT STACK IN EMM
        MOV     SP, 400                 ; SET SP FOR PUSHES
        MOV     DI, SP                  ; SAVE THIS NUMBER
        OUT     PPI_PORT, AL            ; ENABLE TIMER
EPL:    DB      60H                     ; PUSH THE REGISTERS
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        DB      60H                     ;
        MOV     SP, DI                  ; PUT THE STACK BACK
        LOOP    EPL                     ; LOOP UNTIL DONE
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        MOV     SS, DX                  ; RESTORE ORIGINAL STACK
        MOV     SP, BP                  ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_WEMPTIME       ENDP

;***************************************************************;
;                                                               ;
;       _BEMMTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP MOVSB INSTRUCTION                 ;
;                                                               ;
;***************************************************************;

                PUBLIC  _BEMMTIME
_BEMMTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DS                      ; SAVE DS
        PUSH    ES                      ; SAVE ES
        PUSH    SI                      ; SAVE SI
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, EMMBASE             ; SET UP EMM BASE ADDRESS
        MOV     ES, DI                  ;
        MOV     DS, DI                  ;
        XOR     DI, DI                  ; ES:DI -> TEST SEGMENT
        XOR     SI, SI                  ; DS:SI -> TEST SEGMENT
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP MOVSB                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     SI                      ; RESTORE SI
        POP     ES                      ; RESTORE ES
        POP     DS                      ; RESTORE DS
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_BEMMTIME       ENDP

;***************************************************************;
;                                                               ;
;       _WEMMTIME                                               ;
;                                                               ;
;       TIME EXECUTION OF REP MOVSW INSTRUCTION                 ;
;                                                               ;
;***************************************************************;

                PUBLIC  _WEMMTIME
_WEMMTIME       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSH    DS                      ; SAVE DS
        PUSH    ES                      ; SAVE ES
        PUSH    SI                      ; SAVE SI
        PUSH    DI                      ; SAVE DI
        CALL    SETUP_TIMER             ; SET UP TIMER
        MOV     DI, EMMBASE             ; SET UP EMM BASE ADDRESS
        MOV     ES, DI                  ;
        MOV     DS, DI                  ;
        XOR     DI, DI                  ; ES:DI -> TEST SEGMENT
        XOR     SI, SI                  ; DS:SI -> TEST SEGMENT
        MOV     CX, [BP+4]              ; GET COUNT ARGUMENT
        IN      AL, PPI_PORT            ; GET CURRENT CONTROL
        MOV     BL, AL                  ; SAVE IN BL
        OR      AX, 1                   ; SET TIMER ENABLE BIT
        CLI                             ; STOP INTERRUPTS
        CLD                             ; SET FORWARD DIRECTION
        OUT     PPI_PORT, AL            ; ENABLE TIMER
        REP MOVSW                       ; RUN TEST
        MOV     AL, BL                  ; RESTORE CONTROL VALUE
        OUT     PPI_PORT, AL            ;
        STI                             ; START INTERRUPTS
        CALL    GET_TIMER               ; OBTAIN FINAL COUNT
        POP     DI                      ; RESTORE DI
        POP     SI                      ; RESTORE SI
        POP     ES                      ; RESTORE ES
        POP     DS                      ; RESTORE DS
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_WEMMTIME       ENDP

;***************************************************************;
;                                                               ;
;       _SETUP_EMM                                              ;
;                                                               ;
;       SET UP EXPANDED MEMORY AND RETURN THE BASE              ;
;                                                               ;
;***************************************************************;

                PUBLIC  _SETUP_EMM
_SETUP_EMM      PROC    NEAR

        PUSH    BP                      ; SAVE REGISTERS
        PUSH    ES                      ;
        PUSH    SI                      ;
        PUSH    DI                      ;
        MOV     AH, 35H                 ; GET EMM INTERRUPT
        MOV     AL, 67H                 ; VECTOR
        INT     21H                     ;
        MOV     AX, ES                  ; CHECK FOR VALID BASE
        MOV     BX, CS                  ; MUST BE BELOW CS
        CMP     AX, BX                  ;
        JA      SENO                    ; JUMP IF NOT GOOD
        MOV     DI, 000AH               ; OFFSET OF DRIVER NAME
        LEA     SI, EMM_NAME            ; COMPARE STRING
        MOV     CX, 8                   ; LENGTH OF STRING
        CLD                             ;
        REPE    CMPSB                   ; COMPARE THE NAME
        JNE     SENO                    ; JUMP IF NO GOOD
                                        ;
SE1:    MOV     AH, 40H                 ; FUNCTION 1:
        INT     67H                     ; GET MANAGER STATUS
        CMP     AH, 82H                 ; CHECK FOR BUSY
        JE      SE1                     ; TRY AGAIN IF BUSY
        OR      AH, AH                  ; CHECK FOR ERROR
        JNZ     SENO                    ; JUMP ON ERROR
                                        ;
SE2:    MOV     AH, 41H                 ; FUNCTION 2:
        INT     67H                     ; GET PAGE FRAME BASE
        CMP     AH, 82H                 ; CHECK FOR BUSY
        JE      SE2                     ; TRY AGAIN IF BUSY
        OR      AH, AH                  ; CHECK FOR ERROR
        JNZ     SENO                    ; JUMP ON ERROR
        MOV     EMMBASE, BX             ; SAVE THE BASE
                                        ;
SE3:    MOV     AH, 42H                 ; FUNCTION 3:
        INT     67H                     ; GET NUMBER OF PAGES
        CMP     AH, 82H                 ; CHECK FOR BUSY
        JE      SE3                     ; TRY AGAIN IF BUSY
        OR      AH, AH                  ; CHECK FOR ERROR
        JNZ     SENO                    ; JUMP ON ERROR
        OR      BX, BX                  ; CHECK UNALLOCATED PAGES
        JZ      SENO                    ; JUMP IF NONE AVAILABLE
                                        ;
SE4:    MOV     AH, 43H                 ; FUNCTION 4:
        MOV     BX, 1                   ; ALLOCATE ONE PAGE
        INT     67H                     ;
        CMP     AH, 82H                 ; CHECK FOR BUSY
        JE      SE4                     ; TRY AGAIN IF BUSY
        OR      AH, AH                  ; CHECK FOR ERROR
        JNZ     SENO                    ; JUMP ON ERROR
        MOV     PID, DX                 ; SAVE THE PROCESS ID
                                        ;
SE5:    MOV     AH, 44H                 ; FUNCTION 5:
        XOR     BX, BX                  ; MAP THE PAGE TO
        XOR     AL, AL                  ;  FRAME BASE
        INT     67H                     ;
        CMP     AH, 82H                 ; CHECK FOR BUSY
        JE      SE5                     ; TRY AGAIN IF BUSY
        OR      AH, AH                  ; CHECK FOR ERROR
        JNZ     SENC                    ; JUMP ON ERROR
                                        ;
        XOR     AX, AX                  ;
        POP     DI                      ; RESTORE REGISTERS
        POP     SI                      ;
        POP     ES                      ;
        POP     BP                      ;
        RET                             ; RETURN 0

SENC:   MOV     AH, 45H                 ; FUNCTION 6:
        INT     67H                     ; CLOSE EMM
        CMP     AH, 82H                 ; CHECK FOR BUSY
        JE      SENC                    ; TRY AGAIN IF BUSY
SENO:   MOV     AX, 0FFFFH              ;
        POP     DI                      ; RESTORE REGISTERS
        POP     SI                      ;
        POP     ES                      ;
        POP     BP                      ;
        RET                             ; RETURN -1

_SETUP_EMM      ENDP

;***************************************************************;
;                                                               ;
;       _FINISH_EMM                                             ;
;                                                               ;
;       CLOSE THE EMM DEVICE, RELEASE THE PAGE                  ;
;                                                               ;
;***************************************************************;

                PUBLIC  _FINISH_EMM
_FINISH_EMM     PROC    NEAR

        PUSH    BP                      ; SAVE REGISTERS
        PUSH    ES                      ;
        PUSH    SI                      ;
        PUSH    DI                      ;
SE6:    MOV     AH, 45H                 ; FUNCTION 6:
        MOV     DX, PID                 ; CLOSE EMM
        INT     67H                     ;
        CMP     AH, 82H                 ; CHECK FOR BUSY
        JE      SE6                     ; TRY AGAIN IF BUSY
        POP     DI                      ; RESTORE REGISTERS
        POP     SI                      ;
        POP     ES                      ;
        POP     BP                      ;
        RET                             ; RETURN

_FINISH_EMM     ENDP

;***************************************************************;
;                                                               ;
;       SETUP_TIMER                                             ;
;                                                               ;
;       SET UP THE TIMER FOR MAXIMUM COUNT, TO TIME A RUN       ;
;                                                               ;
;***************************************************************;

SETUP_TIMER     PROC    NEAR

        PUSH    AX                      ; SAVE AX
        IN      AL, PPI_PORT            ; STOP THE TIMER
        AND     AL, 0FCH                ;
        OUT     PPI_PORT, AL            ;
        MOV     AL, 0B4H                ; INITIALIZE THE TIMER
        OUT     TIMER_CTRL, AL          ;
        MOV     AL, 0                   ; CLEAR THE COUNT
        OUT     TIMER2_PORT, AL         ;
        NOP                             ;
        OUT     TIMER2_PORT, AL         ;
        POP     AX                      ; RESTORE AX
        RET                             ; RETURN

SETUP_TIMER     ENDP


;***************************************************************;
;                                                               ;
;       GET_TIMER                                               ;
;                                                               ;
;       TAKE THE COUNT FROM THE TIMER                           ;
;                                                               ;
;***************************************************************;

GET_TIMER       PROC    NEAR

        PUSH    BX                      ; SAVE REGISTERS
        IN      AL, TIMER2_PORT         ; GET LOW BYTE OF TIME
        MOV     AH, AL                  ;
        IN      AL, TIMER2_PORT         ; GET HIGH BYTE
        XCHG    AL, AH                  ; TIME IN AX
        NEG     AX                      ; CORRECT FOR COUNT-DOWN
        POP     BX                      ; RESTORE REGISTERS
        RET                             ; RETURN

GET_TIMER       ENDP

;***************************************************************;
;                                                               ;
;       _NDP_PRESENT                                            ;
;                                                               ;
;       CHECK IF 80287 IS PRESENT                               ;
;                                                               ;
;***************************************************************;

                PUBLIC  _NDP_PRESENT
_NDP_PRESENT    PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        INT     11H                     ; BIOS EQUIP CHECK
        TEST    AL,02H                  ; IS 80287 BIT SET?
        JZ      NO                      ; NO MEANS NO 80287
        MOV     AX,01h                  ; RETURN TRUE
        JMP     NDPEXIT                 ; ALL DONE
NO:     XOR     AX,AX                   ; SET AX TO FALSE
NDPEXIT:MOV     SP, BP                  ; RESTORE SP
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_NDP_PRESENT    ENDP

;***************************************************************;
;                                                               ;
;       _CPU_TYPE                                               ;
;                                                               ;
;       CHECK IF CPU IS 8086/8088, 80286, 80386                 ;
;                                                               ;
;***************************************************************;

                PUBLIC  _CPU_TYPE
_CPU_TYPE       PROC    NEAR

        PUSH    BP                      ; SAVE FRAME
        MOV     BP, SP                  ;
        PUSHF                           ;
        XOR     AX,AX                   ; ZERO AX
        PUSH    AX                      ;
        POPF                            ; TRY TO PUT 0 INTO FLAGS
        PUSHF                           ;
        POP     AX                      ; SEE WHAT WENT IN FLAGS
        AND     AX,0F000H               ; MASK OFF HIGH FLAG BITS
        CMP     AX,0F000H               ; WAS HIGH NIBBLE ONES
        JE      _88                     ; IS 8086 OR 8088
        MOV     AX,0F000H               ; TRY TO SET HIGH BITS
        PUSH    AX                      ;
        POPF                            ; IN THE FLAGS
        PUSHF                           ;
        POP     AX                      ; LOOK AT ACTUAL FLAGS
        AND     AX,0F000H               ; ANY HIGH BITS SET?
        JE      _286                    ; IS 80286
_386:   MOV     AX,03                   ; IS AN 80386
        JMP     CTEXIT                  ;
_286:   MOV     AX,02                   ; IS AN 80286
        JMP     CTEXIT                  ;
_88:    MOV     AX,00                   ; IS AN 8086/8088
CTEXIT: POPF                            ; RESTORE ORIGINAL FLAGS
        MOV     SP, BP                  ; RESTORE SP
        POP     BP                      ; RESTORE BP
        RET                             ; RETURN

_CPU_TYPE       ENDP


_TEXT           ENDS

                END
