From 5a0cb68e43eacc98d275baef08296f154f3ae6dd Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Tue, 25 Jul 2006 11:16:03 +0000 Subject: Moved some assembly optimizations to the target tree git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10318 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/sh/memmove-sh.S | 220 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100755 firmware/target/sh/memmove-sh.S (limited to 'firmware/target/sh/memmove-sh.S') diff --git a/firmware/target/sh/memmove-sh.S b/firmware/target/sh/memmove-sh.S new file mode 100755 index 0000000000..9ae9ae5fa2 --- /dev/null +++ b/firmware/target/sh/memmove-sh.S @@ -0,0 +1,220 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Jens Arnold + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" + + .section .icode,"ax",@progbits + + .align 2 + .global _memmove + .type _memmove,@function + +/* Moves bytes of data in memory from to + * Regions may overlap. + * This version is optimized for speed, and needs the corresponding memcpy + * implementation for the forward copy branch. + * + * arguments: + * r4 - destination address + * r5 - source address + * r6 - length + * + * return value: + * r0 - destination address (like ANSI version) + * + * register usage: + * r0 - data / scratch + * r1 - 2nd data / scratch + * r2 - scratch + * r3 - last long bound / adjusted start address (only if >= 11 bytes) + * r4 - current dest address + * r5 - source start address + * r6 - current source address + * + * The instruction order is devised in a way to utilize the pipelining + * of the SH1 to the max. The routine also tries to utilize fast page mode. + */ + +_memmove: + cmp/hi r4,r5 /* source > destination */ + bf .backward /* no: backward copy */ + mov.l .memcpy_fwd,r0 + jmp @r0 + mov r4,r7 /* store dest for returning */ + + .align 2 +.memcpy_fwd: + .long ___memcpy_fwd_entry + +.backward: + add r6,r4 /* r4 = destination end */ + mov #11,r0 + cmp/hs r0,r6 /* at least 11 bytes to copy? (ensures 2 aligned longs) */ + add #-8,r5 /* adjust for late decrement (max. 2 longs) */ + add r5,r6 /* r6 = source end - 8 */ + bf .start_b2r /* no: jump directly to byte loop */ + + mov #-4,r3 /* r3 = 0xfffffffc */ + and r6,r3 /* r3 = last source long bound */ + cmp/hi r3,r6 /* already aligned? */ + bf .end_b1r /* yes: skip leading byte loop */ + +.loop_b1r: + mov.b @(7,r6),r0 /* load byte */ + add #-1,r6 /* decrement source addr */ + mov.b r0,@-r4 /* store byte */ + cmp/hi r3,r6 /* runs r6 down to last long bound */ + bt .loop_b1r + +.end_b1r: + mov #3,r1 + and r4,r1 /* r1 = dest alignment offset */ + mova .jmptab_r,r0 + mov.b @(r0,r1),r1 /* select appropriate main loop.. */ + add r0,r1 + mov r5,r3 /* copy start adress to r3 */ + jmp @r1 /* ..and jump to it */ + add #7,r3 /* adjust end addr for main loops doing 2 longs/pass */ + + /** main loops, copying 2 longs per pass to profit from fast page mode **/ + + /* long aligned destination (fastest) */ + .align 2 +.loop_do0r: + mov.l @r6,r1 /* load first long */ + add #-8,r6 /* decrement source addr */ + mov.l @(12,r6),r0 /* load second long */ + cmp/hi r3,r6 /* runs r6 down to first or second long bound */ + mov.l r0,@-r4 /* store second long */ + mov.l r1,@-r4 /* store first long; NOT ALIGNED - no speed loss here! */ + bt .loop_do0r + + add #-4,r3 /* readjust end address */ + cmp/hi r3,r6 /* first long left? */ + bf .start_b2r /* no, jump to trailing byte loop */ + + mov.l @(4,r6),r0 /* load first long */ + add #-4,r6 /* decrement source addr */ + bra .start_b2r /* jump to trailing byte loop */ + mov.l r0,@-r4 /* store first long */ + + /* word aligned destination (long + 2) */ + .align 2 +.loop_do2r: + mov.l @r6,r1 /* load first long */ + add #-8,r6 /* decrement source addr */ + mov.l @(12,r6),r0 /* load second long */ + cmp/hi r3,r6 /* runs r6 down to first or second long bound */ + mov.w r0,@-r4 /* store low word of second long */ + xtrct r1,r0 /* extract low word of first long & high word of second long */ + mov.l r0,@-r4 /* and store as long */ + shlr16 r1 /* get high word of first long */ + mov.w r1,@-r4 /* and store it */ + bt .loop_do2r + + add #-4,r3 /* readjust end address */ + cmp/hi r3,r6 /* first long left? */ + bf .start_b2r /* no, jump to trailing byte loop */ + + mov.l @(4,r6),r0 /* load first long & decrement source addr */ + add #-4,r6 /* decrement source addr */ + mov.w r0,@-r4 /* store low word */ + shlr16 r0 /* get high word */ + bra .start_b2r /* jump to trailing byte loop */ + mov.w r0,@-r4 /* and store it */ + + /* jumptable for loop selector */ + .align 2 +.jmptab_r: + .byte .loop_do0r - .jmptab_r /* placed in the middle because the SH1 */ + .byte .loop_do1r - .jmptab_r /* loads bytes sign-extended. Otherwise */ + .byte .loop_do2r - .jmptab_r /* the last loop would be out of reach */ + .byte .loop_do3r - .jmptab_r /* of the offset range. */ + + /* byte aligned destination (long + 1) */ + .align 2 +.loop_do1r: + mov.l @r6,r1 /* load first long */ + add #-8,r6 /* decrement source addr */ + mov.l @(12,r6),r0 /* load second long */ + cmp/hi r3,r6 /* runs r6 down to first or second long bound */ + mov.b r0,@-r4 /* store low byte of second long */ + shlr8 r0 /* get upper 3 bytes */ + mov r1,r2 /* copy first long */ + shll16 r2 /* move low byte of first long all the way up, .. */ + shll8 r2 + or r2,r0 /* ..combine with the 3 bytes of second long.. */ + mov.l r0,@-r4 /* ..and store as long */ + shlr8 r1 /* get middle 2 bytes */ + mov.w r1,@-r4 /* store as word */ + shlr16 r1 /* get upper byte */ + mov.b r1,@-r4 /* and store */ + bt .loop_do1r + + add #-4,r3 /* readjust end address */ +.last_do13r: + cmp/hi r3,r6 /* first long left? */ + bf .start_b2r /* no, jump to trailing byte loop */ + + nop /* alignment */ + mov.l @(4,r6),r0 /* load first long */ + add #-4,r6 /* decrement source addr */ + mov.b r0,@-r4 /* store low byte */ + shlr8 r0 /* get middle 2 bytes */ + mov.w r0,@-r4 /* store as word */ + shlr16 r0 /* get upper byte */ + bra .start_b2r /* jump to trailing byte loop */ + mov.b r0,@-r4 /* and store */ + + /* byte aligned destination (long + 3) */ + .align 2 +.loop_do3r: + mov.l @r6,r1 /* load first long */ + add #-8,r6 /* decrement source addr */ + mov.l @(12,r6),r0 /* load second long */ + mov r1,r2 /* copy first long */ + mov.b r0,@-r4 /* store low byte of second long */ + shlr8 r0 /* get middle 2 bytes */ + mov.w r0,@-r4 /* store as word */ + shlr16 r0 /* get upper byte */ + shll8 r2 /* move lower 3 bytes of first long one up.. */ + or r2,r0 /* ..combine with the 1 byte of second long.. */ + mov.l r0,@-r4 /* ..and store as long */ + shlr16 r1 /* get upper byte of first long */ + shlr8 r1 + cmp/hi r3,r6 /* runs r6 down to first or second long bound */ + mov.b r1,@-r4 /* ..and store */ + bt .loop_do3r + + bra .last_do13r /* handle first longword: reuse routine for (long + 1) */ + add #-4,r3 /* readjust end address */ + + /* trailing byte loop: copies 0..3 bytes (or all for < 11 in total) */ + .align 2 +.loop_b2r: + mov.b @(7,r6),r0 /* load byte */ + add #-1,r6 /* decrement source addr */ + mov.b r0,@-r4 /* store byte */ +.start_b2r: + cmp/hi r5,r6 /* runs r6 down to start address */ + bt .loop_b2r + + rts + mov r4,r0 /* return dest start address */ +.end: + .size _memmove,.end-_memmove -- cgit v1.2.3