windows-nt/Source/XPSP1/NT/base/mvdm/wow16/mmsystem/hmemcpy.asm
2020-09-26 16:20:57 +08:00

249 lines
4.8 KiB
NASM

; 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,<NEAR,PASCAL,PUBLIC,NODATA>,<di>
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,<NEAR,PASCAL,PUBLIC,NODATA>,<>
; ParmD lpDst
; ParmD lpSrc
; ParmD cbMem
cBegin <nogen>
mov ax,__WinFlags
test ax,WF_CPU286
jz MemCopy386
jmp NEAR PTR MemCopy286
cEnd <nogen>
cProc MemCopy386,<NEAR,PASCAL,PUBLIC,NODATA>,<ds>
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,<NEAR,PASCAL,PUBLIC,NODATA>,<ds,si,di>
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