249 lines
4.8 KiB
NASM
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
|