2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A .file "__align_cpy_2.s"
2N/A
2N/A/*
2N/A * __align_cpy_2(s1, s2, len)
2N/A *
2N/A * Copy s2 to s1, always copy n bytes.
2N/A * Note: this does not work for overlapped copies, bcopy() does
2N/A * This routine is copied from memcpy.s, with all values doubled.
2N/A * No attempt has been made to improve the comments or performance.
2N/A *
2N/A */
2N/A
2N/A#include <sys/asm_linkage.h>
2N/A
2N/A ENTRY(__align_cpy_2)
2N/A cmp %o0, %o1
2N/A be,pn %xcc, .done ! Identical addresses--done.
2N/A mov %o0, %g5 ! save des address for return val
2N/A cmp %o2, 18 ! for small counts copy bytes
2N/A ble,pn %xcc, .dbytecp
2N/A andcc %o1, 6, %o5 ! is src 8-byte aligned
2N/A bz,pn %xcc, .aldst
2N/A cmp %o5, 4 ! is src 4-byte aligned
2N/A be,pt %xcc, .s2algn
2N/A cmp %o5, 6 ! src is 2-byte aligned
2N/A.s1algn:lduh [%o1], %o3 ! move 2 or 6 bytes to align it
2N/A inc 2, %o1
2N/A sth %o3, [%g5] ! move 2 bytes to align src
2N/A inc 2, %g5
2N/A bne,pt %xcc, .s2algn
2N/A dec 2, %o2
2N/A b .ald ! now go align dest
2N/A andcc %g5, 6, %o5
2N/A
2N/A.s2algn:lduw [%o1], %o3 ! know src is 4-byte aligned
2N/A inc 4, %o1
2N/A srlx %o3, 16, %o4
2N/A sth %o4, [%g5] ! have to do 2-bytes,
2N/A sth %o3, [%g5 + 2] ! don't know dst alignment
2N/A inc 4, %g5
2N/A dec 4, %o2
2N/A
2N/A.aldst: andcc %g5, 6, %o5 ! align the destination address
2N/A.ald: bz,pn %xcc, .w4cp
2N/A cmp %o5, 4
2N/A bz,pn %xcc, .w2cp
2N/A cmp %o5, 6
2N/A.w3cp: ldx [%o1], %o4
2N/A inc 8, %o1
2N/A srlx %o4, 48, %o5
2N/A sth %o5, [%g5]
2N/A bne,pt %xcc, .w1cp
2N/A inc 2, %g5
2N/A dec 2, %o2
2N/A andn %o2, 6, %o3 ! o3 is aligned word count
2N/A sub %o1, %g5, %o1 ! g5 gets the difference
2N/A
2N/A1: sllx %o4, 16, %g1 ! save residual bytes
2N/A ldx [%o1+%g5], %o4
2N/A deccc 8, %o3
2N/A srlx %o4, 48, %o5 ! merge with residual
2N/A or %o5, %g1, %g1
2N/A stx %g1, [%g5]
2N/A bnz,pt %xcc, 1b
2N/A inc 8, %g5
2N/A sub %o1, 6, %o1 ! used two bytes of last word read
2N/A b 7f
2N/A and %o2, 6, %o2
2N/A
2N/A.w1cp: srlx %o4, 16, %o5
2N/A st %o5, [%g5]
2N/A inc 4, %g5
2N/A dec 6, %o2
2N/A andn %o2, 6, %o3
2N/A sub %o1, %g5, %o1 ! g5 gets the difference
2N/A
2N/A2: sllx %o4, 48, %g1 ! save residual bytes
2N/A ldx [%o1+%g5], %o4
2N/A deccc 8, %o3
2N/A srlx %o4, 16, %o5 ! merge with residual
2N/A or %o5, %g1, %g1
2N/A stx %g1, [%g5]
2N/A bnz,pt %xcc, 2b
2N/A inc 8, %g5
2N/A sub %o1, 2, %o1 ! used six bytes of last word read
2N/A b 7f
2N/A and %o2, 6, %o2
2N/A
2N/A.w2cp: ldx [%o1], %o4
2N/A inc 8, %o1
2N/A srlx %o4, 32, %o5
2N/A st %o5, [%g5]
2N/A inc 4, %g5
2N/A dec 4, %o2
2N/A andn %o2, 6, %o3 ! o3 is aligned word count
2N/A sub %o1, %g5, %o1 ! g5 gets the difference
2N/A
2N/A3: sllx %o4, 32, %g1 ! save residual bytes
2N/A ldx [%o1+%g5], %o4
2N/A deccc 8, %o3
2N/A srlx %o4, 32, %o5 ! merge with residual
2N/A or %o5, %g1, %g1
2N/A stx %g1, [%g5]
2N/A bnz,pt %xcc, 3b
2N/A inc 8, %g5
2N/A sub %o1, 4, %o1 ! used four bytes of last word read
2N/A b 7f
2N/A and %o2, 6, %o2
2N/A
2N/A.w4cp: andn %o2, 6, %o3 ! o3 is aligned word count
2N/A sub %o1, %g5, %o1 ! g5 gets the difference
2N/A
2N/A1: ldx [%o1+%g5], %o4 ! read from address
2N/A deccc 8, %o3 ! decrement count
2N/A stx %o4, [%g5] ! write at destination address
2N/A bg,pt %xcc, 1b
2N/A inc 8, %g5 ! increment to address
2N/A b 7f
2N/A and %o2, 6, %o2 ! number of leftover bytes, if any
2N/A
2N/A !
2N/A ! differenced byte copy, works with any alignment
2N/A !
2N/A.dbytecp:
2N/A b 7f
2N/A sub %o1, %g5, %o1 ! g5 gets the difference
2N/A
2N/A4: sth %o4, [%g5] ! write to address
2N/A inc 2, %g5 ! inc to address
2N/A7: deccc 2, %o2 ! decrement count
2N/A bge,a,pt %xcc,4b ! loop till done
2N/A lduh [%o1+%g5], %o4 ! read from address
2N/A.done:
2N/A retl
2N/A nop
2N/A
2N/A SET_SIZE(__align_cpy_2)