/* $OpenBSD: memcpy.S,v 1.1.1.1 2006/10/10 22:07:10 miod Exp $ */ /* $NetBSD: memcpy.S,v 1.2 2006/04/22 23:53:47 uwe Exp $ */ /* * Copyright (c) 2000 SHIMIZU Ryo * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #if !defined(MEMCOPY) && !defined(MEMMOVE) && !defined(BCOPY) #define MEMCOPY #endif #if defined(MEMCOPY) || defined(MEMMOVE) #define REG_DST0 r3 #define REG_SRC r5 #define REG_DST r4 #else #define REG_SRC r4 #define REG_DST r5 #endif #define REG_LEN r6 #if defined(MEMCOPY) ENTRY(memcpy) #elif defined(MEMMOVE) ENTRY(memmove) #elif defined(BCOPY) ENTRY(bcopy) #endif #ifdef REG_DST0 mov REG_DST,REG_DST0 #endif cmp/eq REG_DST,REG_SRC /* if ( src == dst ) return; */ bt/s bcopy_return cmp/hi REG_DST,REG_SRC bf/s bcopy_overlap mov REG_SRC,r0 xor REG_DST,r0 and #3,r0 mov r0,r1 tst r0,r0 /* (src ^ dst) & 3 */ bf/s word_align longword_align: tst REG_LEN,REG_LEN /* if ( len==0 ) return; */ bt/s bcopy_return mov REG_SRC,r0 tst #1,r0 /* if ( src & 1 ) */ bt 1f mov.b @REG_SRC+,r0 /* *dst++ = *src++; */ add #-1,REG_LEN mov.b r0,@REG_DST add #1,REG_DST 1: mov #1,r0 cmp/hi r0,REG_LEN /* if ( (len > 1) && */ bf/s 1f mov REG_SRC,r0 tst #2,r0 /* (src & 2) { */ bt 1f mov.w @REG_SRC+,r0 /* *((unsigned short*)dst)++ = *((unsigned short*)src)++; */ add #-2,REG_LEN /* len -= 2; */ mov.w r0,@REG_DST add #2,REG_DST /* } */ 1: mov #3,r1 cmp/hi r1,REG_LEN /* while ( len > 3 ) { */ bf/s no_align_delay tst REG_LEN,REG_LEN 2: mov.l @REG_SRC+,r0 /* *((unsigned long*)dst)++ = *((unsigned long*)src)++; */ add #-4,REG_LEN /* len -= 4; */ mov.l r0,@REG_DST cmp/hi r1,REG_LEN bt/s 2b add #4,REG_DST /* } */ bra no_align_delay tst REG_LEN,REG_LEN word_align: mov r1,r0 tst #1,r0 bf/s no_align_delay tst REG_LEN,REG_LEN /* if ( len == 0 ) return; */ bt bcopy_return mov REG_SRC,r0 /* if ( src & 1 ) */ tst #1,r0 bt 1f mov.b @REG_SRC+,r0 /* *dst++ = *src++; */ add #-1,REG_LEN mov.b r0,@REG_DST add #1,REG_DST 1: mov #1,r1 cmp/hi r1,REG_LEN /* while ( len > 1 ) { */ bf/s no_align_delay tst REG_LEN,REG_LEN 2: mov.w @REG_SRC+,r0 /* *((unsigned short*)dst)++ = *((unsigned short*)src)++; */ add #-2,REG_LEN /* len -= 2; */ mov.w r0,@REG_DST cmp/hi r1,REG_LEN bt/s 2b add #2,REG_DST /* } */ no_align: tst REG_LEN,REG_LEN /* while ( len!= ) { */ no_align_delay: bt bcopy_return 1: mov.b @REG_SRC+,r0 /* *dst++ = *src++; */ add #-1,REG_LEN /* len--; */ mov.b r0,@REG_DST tst REG_LEN,REG_LEN bf/s 1b add #1,REG_DST /* } */ bcopy_return: rts #ifdef REG_DST0 mov REG_DST0,r0 #else nop #endif bcopy_overlap: add REG_LEN,REG_SRC add REG_LEN,REG_DST mov REG_SRC,r0 xor REG_DST,r0 and #3,r0 mov r0,r1 tst r0,r0 /* (src ^ dst) & 3 */ bf/s ov_word_align ov_longword_align: tst REG_LEN,REG_LEN /* if ( len==0 ) return; */ bt/s bcopy_return mov REG_SRC,r0 tst #1,r0 /* if ( src & 1 ) */ bt 1f add #-1,REG_SRC /* *--dst = *--src; */ mov.b @REG_SRC,r0 mov.b r0,@-REG_DST add #-1,REG_LEN 1: mov #1,r0 cmp/hi r0,REG_LEN /* if ( (len > 1) && */ bf/s 1f mov REG_SRC,r0 tst #2,r0 /* (src & 2) { */ bt 1f add #-2,REG_SRC /* *--((unsigned short*)dst) = *--((unsigned short*)src); */ mov.w @REG_SRC,r0 add #-2,REG_LEN /* len -= 2; */ mov.w r0,@-REG_DST /* } */ 1: mov #3,r1 cmp/hi r1,REG_LEN /* while ( len > 3 ) { */ bf/s ov_no_align_delay tst REG_LEN,REG_LEN 2: add #-4,REG_SRC mov.l @REG_SRC,r0 /* *((unsigned long*)dst)++ = *((unsigned long*)src)++; */ add #-4,REG_LEN /* len -= 4; */ cmp/hi r1,REG_LEN bt/s 2b mov.l r0,@-REG_DST /* } */ bra ov_no_align_delay tst REG_LEN,REG_LEN ov_word_align: mov r1,r0 tst #1,r0 bf/s ov_no_align_delay tst REG_LEN,REG_LEN /* if ( len == 0 ) return; */ bt bcopy_return mov REG_SRC,r0 /* if ( src & 1 ) */ tst #1,r0 bt 1f add #-1,REG_SRC mov.b @REG_SRC,r0 /* *--dst = *--src; */ add #-1,REG_LEN mov.b r0,@-REG_DST 1: mov #1,r1 cmp/hi r1,REG_LEN /* while ( len > 1 ) { */ bf/s ov_no_align_delay tst REG_LEN,REG_LEN 2: add #-2,REG_SRC mov.w @REG_SRC,r0 /* *--((unsigned short*)dst) = *--((unsigned short*)src); */ add #-2,REG_LEN /* len -= 2; */ cmp/hi r1,REG_LEN bt/s 2b mov.w r0,@-REG_DST /* } */ ov_no_align: tst REG_LEN,REG_LEN /* while ( len!= ) { */ ov_no_align_delay: bt 9f 1: add #-1,REG_SRC mov.b @REG_SRC,r0 /* *--dst = *--src; */ add #-1,REG_LEN /* len--; */ tst REG_LEN,REG_LEN bf/s 1b mov.b r0,@-REG_DST /* } */ 9: rts #ifdef REG_DST0 mov REG_DST0,r0 #else nop #endif