| /* $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 <ryo@misakimix.org> |
| * 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 <machine/asm.h> |
| |
| #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 |