windows-nt/Source/XPSP1/NT/multimedia/media/avi/avifile.16/memcopy.asm

414 lines
7.8 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
; 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
PMODE=1
.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
;---------------------------Public-Routine------------------------------;
; hmemcpy
;
; copy memory
;
; Entry:
; lpSrc HPSTR to copy from
; lpDst HPSTR to copy to
; cbMem DWORD count of bytes to move
;
; NOTE: overlapped copies will work iff lpSrc.sel == lpDst.sel
; [This is a lie. They will always work.]
;
; 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,<FAR,PASCAL,PUBLIC,NODATA>,<>
; ParmD lpDst
; ParmD lpSrc
; ParmD cbMem
cBegin <nogen>
mov ax,__WinFlags
test ax,WF_CPU286
jz fmemcpy386
jmp FAR PTR fmemcpy286
cEnd <nogen>
cProc fmemcpy386,<FAR,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
;
; calculate differance of pointers in "selector" space
;
mov ax,si ; DX:AX = lpSrc
mov dx,ds
mov bx,es ; BX = selector of ptr B
mov cx,__AHSHIFT ; number of selector bits per 64K 'segment'
shr dx,cl ; linearize ptr A
shr bx,cl ; linearize ptr B
;
; DX and BX contain normalized selectors
;
mov ecx,cbMem
sub ax,di
sbb dx,bx ; do long subtraction.
jnc mc_copy_forward
add ax,cx
adc dx,cbMem.hi
jnc mc_copy_forward ; carry, so >0, thus they do hit.
std
add edi,ecx
add esi,ecx
sub edi,4
sub esi,4
push ecx
shr ecx,2 ; get count in DWORDs
rep movs dword ptr es:[edi], dword ptr ds:[esi]
db 67H ; Fix strange 386 bug
add edi,3
add esi,3
pop ecx
and ecx,3
rep movs byte ptr es:[edi], byte ptr ds:[esi]
db 67H ; Fix strange 386 bug
jmp mc386_exit
mc_copy_forward:
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 fmemcpy286,<FAR,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
;
; calculate differance of pointers in "selector" space
;
mov ax,si ; DX:AX = lpSrc
mov dx,ds
mov bx,es ; BX = selector of ptr B
mov cx,__AHSHIFT ; number of selector bits per 64K 'segment'
shr dx,cl ; linearize ptr A
shr bx,cl ; linearize ptr B
;
; DX and BX contain normalized selectors
;
mov cx,cbMem.lo
sub ax,di
sbb dx,bx ; do long subtraction.
jnc forward_copy ; difference is positive, so copy forward
; see if the blocks intersect: is source + count > dest?
; equivalently, is source-dest + count > 0 ?
; sub ax,cx
; sbb dx,0
; jnc next ; This looks wrong. Recheck!
add ax,cx
adc dx,cbMem.hi
jc reverse_copy ; carry, so >0, thus they do hit.
forward_copy:
jmp next
reverse_copy:
; first, we have to set ds:si and es:di to the _ends_ of the blocks
sub cx,1
sbb cbMem.hi,0 ; subtract 2 from (long) count
xor ax,ax
add si,cx
adc ax,cbMem.hi
push cx
mov cx,__AHSHIFT
shl ax,cl
pop cx
mov bx,ds
add ax,bx ; advance DS
mov ds,ax
xor ax,ax
add di,cx
adc ax,cbMem.hi
push cx
mov cx,__AHSHIFT
shl ax,cl
pop cx
mov bx,es
add ax,bx ; advance ES
mov es,ax
add cx,1
adc cbMem.hi,0 ; restore count
;
; DS:SI += Count
; ES:DI += Count
; While Count != 0 Do
; Num = MIN(Count,SI+1,DI+1)
; Reverse Copy "Num" Bytes from DS:SI to ES:DI
; (SI -= Num, DI -= Num)
; Count -= Num
; If Count == 0 Then
; BREAK
; If SI == 0xFFFF Then
; DS -= __AHINCR
; If DI == 0xFFFF Then
; ES -= __AHINCR
;
next_r:
mov ax,si
sub ax,di
sbb bx,bx
and ax,bx
add ax,di ; AX = MIN(SI, DI)
test cbMem.hi,-1 ; is high word not zero?
jnz @f ; at least 64k to go
dec cx
sub ax,cx
sbb bx,bx
and ax,bx
add ax,cx
inc cx
@@:
xor bx,bx
add ax,1 ; AX = Num = MIN(Count-1,SI,DI)+1
adc bx,0 ; bx==1 if exactly 64k
xchg ax,cx
sub ax,cx ; Count -= Num
sbb cbMem.hi,bx
std
shr bx,1
rcr cx,1 ; if bx==1, then cx ends up 0x8000
dec si
dec di
rep movsw
inc si ; realign pointers
inc di
adc cl,cl
rep movsb ; move last byte, if necessary
cld
mov cx,ax ; restore cx
or ax,cbMem.hi
jz done ; If Count == 0 Then BREAK
cmp si,-1 ; if SI wraps, update DS
jne @f
mov ax,ds
sub ax,__AHINCR
mov ds,ax ; update DS if appropriate
@@:
cmp di,-1 ; if DI wraps, update ES
jne next_r
mov ax,es
sub ax,__AHINCR
mov es,ax ; update ES if appropriate
jmp next_r
;
; While Count != 0 Do
; If (Count + SI > 65536) OR (Count + DI > 65536) Then
; Num = Min(65536-SI, 65536-DI)
; Else
; Num = Count
; Copy "Num" Bytes from DS:SI to ES:DI (SI += Num, DI += Num)
; Count -= Num
; If Count == 0 Then
; BREAK
; If SI == 0 Then
; DS += __AHINCR
; If DI == 0 Then
; ES += __AHINCR
;
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
adc cl,cl
rep 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