; mem.asm: ; ; masm -Mx -Zi -DSEGNAME=????? asm.asm ; TITLE MEM.ASM ;**************************************************************** ;* MEM.ASM - Assembly mem-copy routines * ;* for 80286 and 80386 * ;**************************************************************** ; ?PLM=1 ; PASCAL Calling convention is DEFAULT ?WIN=0 ; Windows calling convention .xlist include cmacros.inc include windows.inc .list externA __WinFlags ; in KERNEL externA __AHINCR ; in KERNEL externA __AHSHIFT ; in KERNEL ; The following structure should be used to access high and low ; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi". LONG struc lo dw ? hi dw ? LONG ends FARPOINTER struc off dw ? sel dw ? FARPOINTER ends ; ------------------------------------------------------- ; DATA SEGMENT DECLARATIONS ; ------------------------------------------------------- ifndef SEGNAME SEGNAME equ <_TEXT> endif createSeg %SEGNAME, CodeSeg, word, public, CODE sBegin Data sEnd Data sBegin CodeSeg assumes cs,CodeSeg assumes ds,DATA cProc fstrrchr,, ParmD lsz ParmB c cBegin les di, lsz xor al, al ; Search for terminating NULL mov cx, -1 ; Search forever cld ; Moving forward repne scasb ; Look for the NULL not cx ; Negative value minus 1 gives length dec cx ; CX is always incremented jcxz fstrrchr_fail ; Zero length string fails dec di ; DI is one past character found dec di ; Back up to last character in string mov al, c ; Get character to search for std ; Moving backwards repne scasb ; Look for the character cld ; Reset direction jne fstrrchr_fail ; Fail if not found inc di ; Back up to actual character found mov ax, di ; Return pointer to that character mov dx, es jmp fstrrchr_exit fstrrchr_fail: xor ax, ax ; Return NULL on failure cwd fstrrchr_exit: cEnd ;---------------------------Public-Routine------------------------------; ; MemCopy ; ; copy memory, dons *not* handle overlaped copies. ; ; Entry: ; lpSrc HPSTR to copy from ; lpDst HPSTR to copy to ; cbMem DWORD count of bytes to move ; ; Returns: ; destination pointer ; Error Returns: ; None ; Registers Preserved: ; BP,DS,SI,DI ; Registers Destroyed: ; AX,BX,CX,DX,FLAGS ; Calls: ; nothing ; History: ; ; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa] ; Created. ; Tue 16-Oct-1990 16:41:00 -by- David Maymudes [DavidMay] ; Modified 286 case to work correctly with cbMem >= 64K. ; Changed name to hmemcpy. ; Changed 386 case to copy by longwords ;-----------------------------------------------------------------------; cProc MemCopy,,<> ; ParmD lpDst ; ParmD lpSrc ; ParmD cbMem cBegin mov ax,__WinFlags test ax,WF_CPU286 jz MemCopy386 jmp NEAR PTR MemCopy286 cEnd cProc MemCopy386,, ParmD lpDst ParmD lpSrc ParmD cbMem cBegin .386 push edi push esi cld mov ecx,cbMem jecxz mc386_exit movzx edi,di movzx esi,si lds si,lpSrc les di,lpDst push ecx shr ecx,2 ; get count in DWORDs rep movs dword ptr es:[edi], dword ptr ds:[esi] db 67H pop ecx and ecx,3 rep movs byte ptr es:[edi], byte ptr ds:[esi] db 67H nop mc386_exit: cld pop esi pop edi mov dx,lpDst.sel ; return destination address mov ax,lpDst.off .286 cEnd cProc MemCopy286,, ParmD lpDst ParmD lpSrc ParmD cbMem cBegin mov cx,cbMem.lo ; CX holds count or cx,cbMem.hi ; or with high word jnz @f jmp empty_copy @@: lds si,lpSrc ; DS:SI = src les di,lpDst ; ES:DI = dst next: mov ax,cx dec ax mov ax,di not ax ; AX = 65535-DI mov dx,si not dx ; DX = 65535-SI sub ax,dx sbb bx,bx and ax,bx add ax,dx ; AX = MIN(AX,DX) = MIN(65535-SI,65535-DI) ; problem: ax might have wrapped to zero test cbMem.hi,-1 jnz plentytogo ; at least 64k still to copy dec cx ; this is ok, since high word is zero sub ax,cx sbb bx,bx and ax,bx add ax,cx ; AX = MIN(AX,CX) inc cx plentytogo: xor bx,bx add ax,1 ; AX = Num = MIN(count,65536-SI,65536-DI) ; we must check the carry here! adc bx,0 ; BX could be 1 here, if CX==0 indicating ; exactly 64k to copy xchg ax,cx sub ax,cx ; Count -= Num sbb cbMem.hi,bx shr bx,1 rcr cx,1 ; if bx==1, then cx ends up 0x8000 rep movsw jnc @f movsb ; move last byte, if necessary @@: mov cx,ax ; put low word of count back in cx or ax,cbMem.hi jz done ; If Count == 0 Then BREAK or si,si ; if SI wraps, update DS jnz @f ; mov ax,ds add ax,__AHINCR mov ds,ax ; update DS if appropriate @@: or di,di ; if DI wraps, update ES jnz next ; mov ax,es add ax,__AHINCR mov es,ax ; update ES if appropriate jmp next ; ; Restore registers and return ; done: empty_copy: mov dx,lpDst.sel ; return destination address mov ax,lpDst.off cEnd sEnd sEnd CodeSeg end