/*      $NetBSD: memset.S,v 1.9 2023/01/19 18:03:03 mlelstv Exp $       */

/*
* Copyright 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* 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. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*      This product includes software developed for the NetBSD Project by
*      Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
*    or promote products derived from this software without specific prior
*    written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
* 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.
*/
/*
* Copyright (c) 1995 Mark Brinicombe.
* 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. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*      This product includes software developed by Mark Brinicombe.
* 4. The name of the company nor the name of the author may 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 OR CONTRIBUTORS 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(__ARM_EABI__) && !defined(_BZERO) && !defined(_RUMPKERNEL)
ENTRY(__aeabi_memset)
       mov     r3, r1
       mov     r1, r2
       mov     r2, r3
       b       memset
END(__aeabi_memset)
STRONG_ALIAS(__aeabi_memset4, __aeabi_memset)
STRONG_ALIAS(__aeabi_memset8, __aeabi_memset)

ENTRY(__aeabi_memclr)
       mov     r2, r1
       mov     r1, #0
       b       memset
END(__aeabi_memclr)
STRONG_ALIAS(__aeabi_memclr4, __aeabi_memclr)
STRONG_ALIAS(__aeabi_memclr8, __aeabi_memclr)
#endif

/*
* memset: Sets a block of memory to the specified value
*
* On entry:
*   r0 - dest address
*   r1 - byte to write
*   r2 - number of bytes to write
*
* On exit:
*   r0 - dest address
*/
#ifdef _BZERO
/* LINTSTUB: Func: void bzero(void *, size_t) */
ENTRY(bzero)
       mov     r3, #0x00
#else
/* LINTSTUB: Func: void *memset(void *, int, size_t) */
ENTRY(memset)
       and     r3, r1, #0xff           /* We deal with bytes */
       mov     r1, r2
#endif
       cmp     r1, #0x04               /* Do we have less than 4 bytes */
       mov     ip, r0
       blo     .Lmemset_lessthanfour

       /* Ok first we will word align the address */
       ands    r2, ip, #0x03           /* Get the bottom two bits */
       bne     .Lmemset_wordunaligned  /* The address is not word aligned */

       /* We are now word aligned */
Lmemset_wordaligned:
#ifndef _BZERO
       orr     r3, r3, r3, lsl #8      /* Extend value to 16-bits */
#endif
#ifdef _ARM_ARCH_DWORD_OK
       tst     ip, #0x04               /* Quad-align for Xscale */
#else
       cmp     r1, #0x10
#endif
#ifndef _BZERO
       orr     r3, r3, r3, lsl #16     /* Extend value to 32-bits */
#endif
#ifdef _ARM_ARCH_DWORD_OK
       subne   r1, r1, #0x04           /* Quad-align if necessary */
       strne   r3, [ip], #0x04
       cmp     r1, #0x10
#endif
       blo     .Lmemset_loop4          /* If less than 16 then use words */
       mov     r2, r3                  /* Duplicate data */
       cmp     r1, #0x80               /* If < 128 then skip the big loop */
       blo     .Lmemset_loop32

       /* Do 128 bytes at a time */
Lmemset_loop128:
       subs    r1, r1, #0x80
#ifdef _ARM_ARCH_DWORD_OK
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
#else
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
#endif
       bhi     .Lmemset_loop128
       RETc(eq)                        /* Zero length so just exit */

       add     r1, r1, #0x80           /* Adjust for extra sub */

       /* Do 32 bytes at a time */
Lmemset_loop32:
       subs    r1, r1, #0x20
#ifdef _ARM_ARCH_DWORD_OK
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
#else
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
#endif
       bhi     .Lmemset_loop32
       RETc(eq)                        /* Zero length so just exit */

       adds    r1, r1, #0x10           /* Partially adjust for extra sub */

       /* Deal with 16 bytes or more */
#ifdef _ARM_ARCH_DWORD_OK
       strdhs  r2, r3, [ip], #0x08
       strdhs  r2, r3, [ip], #0x08
#else
       stmiahs ip!, {r2-r3}
       stmiahs ip!, {r2-r3}
#endif
       RETc(eq)                        /* Zero length so just exit */

       addlo   r1, r1, #0x10           /* Possibly adjust for extra sub */

       /* We have at least 4 bytes so copy as words */
Lmemset_loop4:
       subs    r1, r1, #0x04
       strhs   r3, [ip], #0x04
       bhi     .Lmemset_loop4
       RETc(eq)                        /* Zero length so just exit */

#ifdef _ARM_ARCH_DWORD_OK
       /* Compensate for 64-bit alignment check */
       adds    r1, r1, #0x04
       RETc(eq)
       cmp     r1, #2
#else
       cmp     r1, #-2
#endif

       strb    r3, [ip], #0x01         /* Set 1 byte */
       strbhs  r3, [ip], #0x01         /* Set another byte */
       strbhi  r3, [ip]                /* and a third */
       RET                             /* Exit */

Lmemset_wordunaligned:
       rsb     r2, r2, #0x004
       strb    r3, [ip], #0x01         /* Set 1 byte */
       cmp     r2, #0x02
       strbhs  r3, [ip], #0x01         /* Set another byte */
       sub     r1, r1, r2
       strbhi  r3, [ip], #0x01         /* and a third */
       cmp     r1, #0x04               /* More than 4 bytes left? */
       bhs     .Lmemset_wordaligned    /* Yup */

Lmemset_lessthanfour:
       cmp     r1, #0x00
       RETc(eq)                                /* Zero length so exit */
       strb    r3, [ip], #0x01         /* Set 1 byte */
       cmp     r1, #0x02
       strbhs  r3, [ip], #0x01         /* Set another byte */
       strbhi  r3, [ip]                /* and a third */
       RET                             /* Exit */
#ifdef _BZERO
END(bzero)
#else
END(memset)
#endif