DSP

memcpy memcopy 的实现

2019-07-13 15:50发布

  先是VC中的实现直接字符: void * __cdecl memcpy (void * dst, const void * src, size_t count)
{
        
void * ret = dst;

        
/*
         * copy from lower addresses to higher addresses
         */

        
while (count--) {
                
*(char *)dst = *(char *)src;
                dst 
= (char *)dst + 1; //不能对void* 直接加1,因为unknown size
                src 
= (char *)src + 1;
        
}

        
return(ret);
}   void * __cdecl memmove (void * dst, const void * src, size_t count)
{
        
void * ret = dst;

        
if (dst <= src || (char *)dst >= ((char *)src + count)) {
                
/*
                 * Non-Overlapping Buffers
                 * copy from lower addresses to higher addresses
                 */

                
while (count--) {
                        
*(char *)dst = *(char *)src;
                        dst 
= (char *)dst + 1;
                        src 
= (char *)src + 1;
                
}
        
}
        
else {
                
/*
                 * Overlapping Buffers
                 * copy from higher addresses to lower addresses
                 */

                dst 
= (char *)dst + count - 1;
                src 
= (char *)src + count - 1;

                
while (count--) {
                        
*(char *)dst = *(char *)src;
                        dst 
= (char *)dst - 1;
                        src 
= (char *)src - 1;
                
}
        
}

        
return(ret);
}   引用别人的: Intel 80386以上支持的指令集中MOVSD指令和REP指令配合将DWORD32bit)在内存间移动,即在一个时钟周期copy四个字节,整整比MOVSB8bit)指令快了四倍。但是使用MOVSD移动到的目的内存地址必须是32bit对齐的(DWORD-aligned)。简单说明从低位到高位的内存copy如下。 L为要拷贝的总字节数,Dest为目的起始地址,X为从Dest开始没有DWORD-aligned的字节数,Y为要拷贝的DWORD个数,Z为剩余的没有DWORD-aligned字节数。那么有公式如下:   X = (4 – Dest & 3 ) & 3 (bytes)   //低两位为0的地址是DWORD-aligned Y = (L – X) >> 2 (DWORDs)     //整除以4DWORD个数 Z = (L – X – Y * 4) (bytes)   总结一下,对大段的内存移动,用memmove将是非常优化的,相反若用c写的code会降低四倍效率,这就是为什么要用ASM直接实现的原因。   下面是ASM版本的实现: memcpy: 

/*-----------------------------------------------------------------------* 
  *   filename   -   memcpy.cas 
  * 
  *   function(s) 
  *                 memcpy   -   copy   a   block   of   n   bytes   from   src   to   dst 
  *-----------------------------------------------------------------------*/ 
#pragma   inline 
#include    
#include    

#undef   memcpy                                     /*   not   an   intrinsic   */ 

/*-----------------------------------------------------------------------* 

Name                         memcpy   -   copy   a   block   of   n   bytes   from   src   to   dst 

Usage                       void   *memcpy(void   *dst,   const   void   *src,   size_t   n); 

Prototype   in         mem.h   &   string.h 

Description           memcpy   copies     a   block   of   n     bytes   from   src   to     dst. 
                                No   overlap   checking   is   performed. 

Return   value         memcpy   returns   dst 

*------------------------------------------------------------------------*/ 

#if   defined(__FARFUNCS__) 
#include   <_farfunc.h> 
#endif 

#if           1               /*   No   overlap   checking   version   */ 

void   *   _FARFUNC   memcpy(void   *dst,   const   void   *src,   size_t   n) 
{ 
#if   !(LDATA) 
                _ES   =   _DS; 
#endif 
#if           defined(__LARGE__)   ||     defined(__COMPACT__) 
asm           mov           dx,ds                       /*   save   ds   */ 
#endif 
asm           LES_           di,   dst 
asm           LDS_           si,   src 
asm           mov           cx,n 
asm           shr           cx,1 
asm           cld 
asm           rep           movsw 
asm           jnc           cpy_end 
asm           movsb 
cpy_end: 
#if           defined(__LARGE__)   ||   defined(__COMPACT__) 
                asm           mov           ds,dx                       /*   restore   */ 
#endif 
                return(dst); 
} 

#else                       /*   Overlap   checking   version           */ 

void   *   _FARFUNC   memcpy(void   *dst,   const   void   *src,   size_t   n) 
{ 
                movmem(src,dst,n); 
                return(dst); 
} 
#endif 


memmove: 

/*-----------------------------------------------------------------------* 
  *   filename   -   movmem.cas 
  * 
  *   function(s) 
  *                 movmem     -   move   a   block   of   bytes 
  *                 memmove   -   move   a   block   of   bytes 
  *-----------------------------------------------------------------------*/ 
#pragma   inline 
#include    
#include    

/*-----------------------------------------------------------------------* 

Name                         movmem   -   move   a   block   of   bytes 

Usage                       void   movmem(void   *src,   void   *dst,   unsigned   len); 

Prototype   in         mem.h 

Description           movmem   copies   a   block   of   len     bytes   from   src   to   dst.   If   the 
                                source   and     destination   arrays   overlap,   the     copy   direction 
                                is   chosen   so   that   the   data   is   always   copied   correctly. 

Return   value         There   is   no   return   value 

*------------------------------------------------------------------------*/ 
#if   defined(__FARFUNCS__) 
#include   <_farfunc.h> 
#endif 

void   _FARFUNC   movmem(const   void   *src,   void   *dst,   unsigned   len) 
{ 
#if           LDATA 
#if           !defined(__HUGE__) 
                asm           push         ds 
#endif 
                if             (((void   huge   *)src)   <   ((void   huge   *)dst)) 
#else 
                _ES   =   _DS; 
                if             (src   <   dst) 
#endif 
                {               /*   travel   backward,   need   to   adjust   ptrs   later   */ 
                                asm           std 
                                asm           mov           ax,   1 
                } 
                else 
                {               /*   travel   forward,   no   need   to   adjust   ptrs   */ 
                                asm           cld 
                                asm           xor           ax,   ax 
                } 

asm           LDS_         si,   src 
asm           LES_         di,   dst 
asm           mov           cx,   len 

asm           or             ax,   ax 
asm           jz             movit 
asm           add           si,   cx     /*   backward   move,   adjust   ptrs   to   end-1   */ 
asm           dec           si 
asm           add           di,   cx 
asm           dec           di 
movit: 
asm           test         di,   1 
asm           jz             isAligned 
asm           jcxz         done 
asm           movsb 
asm           dec           cx 
isAligned: 
asm           sub           si,   ax     /*   compensate   for   word   moves   */ 
asm           sub           di,   ax 
asm           shr           cx,   1 
asm           rep           movsw 
asm           jnc           noOdd 
asm           add           si,   ax     /*   compensate   for   final   byte   */ 
asm           add           di,   ax 
asm           movsb 
noOdd: 
done: 
asm           cld 

#if           defined(__LARGE__)   ||     defined(__COMPACT__) 
                asm           pop           ds 
#endif 
} 


/*-----------------------------------------------------------------------* 

Name                         memmove   -   move   a   block   of   bytes 

Usage                       void   memmove(void   *dst,   const   void   *scr,   unsigned   len); 

Prototype   in         mem.h 

Description           memmove   copies   a   block   of   len     bytes   from   src   to   dst.   If   the 
                                source   and     destination   arrays   overlap,   the     copy   direction 
                                is   chosen   so   that   the   data   is   always   copied   correctly. 

Return   value         dst 

*------------------------------------------------------------------------*/ 
void   *_CType   _FARFUNC   memmove(   void   *dst,   const   void   *src,   size_t   n   ) 
{ 
        movmem(   (void   *)src,   dst,   n   ); 
        return(   dst   ); 
}