; Program to show how to fast copy with REP MOVS, to fast compare with
; REP CMPS, and to execute large loop with LOOPX instruction
; Written by Erwann Corvellec
IDEAL
P386
DOSSEG
JUMPS
MODEL LARGE, PASCAL
INCLUDE "FRMI.INC"
INCLUDE "MYMACROS.MAC"
STACK 200h
═══════════════════════════════════════════════════════════════════════════════
DATASEG
MEM_TO_ALLOC EQU 400
MEM_TO_ALLOC_STR EQU "400"
LOOPX_CNT EQU 12345h
LOOPX_CNT_STR EQU "12345h"
TCR EQU 13, 10
@MKPS ERRMSG_Bad_CPU, <TCR, "A 386 CPU or greater is needed !", TCR>
@MKPS ERRMSG_V86, <TCR, "Your CPU is running in V86 MODE ! Please remove QEMM386, 386MAX, EMM386, etc.", TCR>
@MKPS ERRMSG_XMS_DRIVER_Error <"Error while initializing XMS driver !", TCR>
@MKPS ERRMSG_Alloc_Error, <TCR, TCR, "Error while allocating ", MEM_TO_ALLOC_STR, "KB of memory...", TCR>
@MKPS ERRMSG_Checking_Error, <TCR, "Error while checking...", TCR>
@MKPS INFOMSG_Copying, <TCR, "Fast copy of ", MEM_TO_ALLOC_STR, "KB from DS:0 to allocated zone (EAX)...", TCR, "EAX=">
@MKPS INFOMSG_Checking, <TCR, TCR, "Checking now...", TCR>
@MKPS INFOMSG_Checking_Successful,<"Checking is successful !", TCR>
@MKPS INFOMSG_Counting, <TCR, "Counting from ", LOOPX_CNT_STR, " downto 1 using LOOPX. Press a key to stop it...", TCR>
═══════════════════════════════════════════════════════════════════════════════
CODESEG
ASSUME CS:@code, DS:@data
PROC Disp_PS NEAR USES AX BX CX DX
ARG PS:NEAR PTR BYTE
Mov AH, 40h
Mov CH, 0
Mov BX, [PS]
Mov CL, [BX]
Inc BX
Mov DX, BX
Mov BX, 1
INT 21h
RET
ENDP
PROC Disp_Hex NEAR USES AX BX CX
ARG Digit:DWORD
Mov CX, 8
@@Print_Loop:
Rol [Digit], 4
Mov AL, [BYTE Digit]
And AL, 0Fh
Cmp AL, 10
JB @@Dec_Number
Add AL, 'A'-'0'-10
@@Dec_Number:
Add AL, '0'
Mov BH, 0
Mov AH, 0Eh
INT 10h
LOOP @@Print_Loop
RET
ENDP
───────────────────────────────────────────────────────────────────────────────
STARTUPCODE
; Release all memory except the amount currently being used
; End of stack is end of non-heap portion of program
Mov BX, SP
Shr BX, 4 ; Convert SP into paragraphs
Inc BX
Mov AX, SS ; Calculate size of program using PSP address in ES
Add BX, AX
Mov AX, ES
Sub BX, AX
Mov AH, 4Ah ; Resize memory block with PSP address in ES
INT 21h
CALL FRMI_START
JNC @@In_FRM
Cmp AH, CPU_80386
JAE @@CPU_Type_OK
CALL Disp_PS, OFFSET ERRMSG_Bad_CPU
@DOS_EXIT 1
@@CPU_Type_OK:
CALL Disp_PS, OFFSET ERRMSG_V86
@DOS_EXIT 1
───────────────────────────────────────────────────────────────────────────────
@@In_FRM:
CALL XMS_INIT
JNC @@XMS_Init_OK
CALL Disp_PS, OFFSET ERRMSG_XMS_DRIVER_Error
@DOS_EXIT 1
───────────────────────────────────────────────────────────────────────────────
@@XMS_Init_OK:
CALL GET_RAM, MEM_TO_ALLOC
JNC @@Enough_Free
CALL Disp_PS, OFFSET ERRMSG_Alloc_Error
@DOS_EXIT 1
@@Enough_Free:
CALL Disp_PS, OFFSET INFOMSG_Copying
CALL Disp_Hex, EAX
Xor BX, BX
Mov ES, BX
@SEG2LIN ESI, <DS>, <0>
Mov EDI, EAX
Mov ECX, MEM_TO_ALLOC*1024
Push EDI ECX
CLD
REP MOVS [BYTE ES:EDI], [ES:ESI] ; This copy ECX bytes ("BYTE") from
; ES:ESI to ES:EDI
; Note that in the source pointer
; (here ES:ESI) the segment can be
; changed in DS, ES, FS or GS !
; But that is nonsense in FRM, because
; ES must be equal to 0 !
; So why would U use another segment ?
Pop ECX EDI
CALL Disp_PS, OFFSET INFOMSG_Checking
Mov ESI, EDI ; Just for you to see how CMPS works...
CLD
REP CMPS [BYTE ES:EDI], [ES:ESI] ; Same principle as above...
CALL FREE_RAM, EAX
JCXZ @@Check_OK
CALL Disp_PS, OFFSET ERRMSG_Checking_Error ; Can we arrive here ?!?
JMP @@Exit
@@Check_OK:
CALL Disp_PS, OFFSET INFOMSG_Checking_Successful
───────────────────────────────────────────────────────────────────────────────
CALL Disp_PS, OFFSET INFOMSG_Counting
Mov ECX, LOOPX_CNT ; Yes, we will use ECX in LOOP instruction
Mov AX, 0E0Dh
Mov BH, 0
@@Loop_X:
@KB_HIT
JNZ @@Exit
Test CL, 110000b
JNZ @@Dont_Disp
CALL Disp_Hex, ECX
INT 10h
@@Dont_Disp:
LOOPX @@Loop_X ; Here's the interesting part
Mov AX, 0B800h ; ES can be used as a standard segment reg
Mov ES, AX
Mov [DWORD ES:2*80], 0CF4BBF4Fh
───────────────────────────────────────────────────────────────────────────────
@@Exit:
@DOS_EXIT 0
END