/*
 * memcpy.c - architecture independent memory copy functions
 *
 * Author ALain Greiner (2016)
 *
 * Copyright (c) UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-MKH.
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <hal_kernel_types.h>
#include <printk.h>

/////////////////////////////////
void * memcpy( void       * dst,
               const void * src,
               uint32_t     size)
{
    uint32_t       * wdst = dst;
    const uint32_t * wsrc = src;

    // word per word copy if both addresses aligned
    if (!((uint32_t) wdst & 3) && !((uint32_t) wsrc & 3) )
    {
        while (size > 3)
        {
            *wdst++ = *wsrc++;
            size -= 4;
        }
    }

    unsigned char *cdst = (unsigned char*)wdst;
    unsigned char *csrc = (unsigned char*)wsrc;

    // byte per byte for last bytes (or not aligned)
    while (size--)
    {
        *cdst++ = *csrc++;
    }
    return dst;
}

//////////////////////////////
void * memset( void     * dst,
               uint32_t   val,
               uint32_t   size)
{
    // build 8 bits and 32 bits values
    uint8_t    byte = (uint8_t)(val & 0xFF);
    uint32_t   word = (val<<24) | (val<<16) | (val<<8) | val;

    // word per word if address aligned
    uint32_t * wdst = (uint32_t *)dst;

    if( (((uint32_t)dst) & 0x3) == 0 )
    {
        while( size > 3 )
        {
            *wdst++ = word;
            size -= 4;
        }
    }

    // byte per byte for last bytes (or not aligned)
    char * cdst = (char *)wdst;

    while( size-- )
    {
        *cdst++ = byte;
    }

    return dst;
}

//////////////////////////////
int memcmp( const void * s1,
            const void * s2,
            uint32_t     n)
{
    const uint8_t * cs1 = s1;
    const uint8_t * cs2 = s2;

    while (n > 0)
    {
        if (*cs1++ != *cs2++)
            return (*--cs1 - *--cs2);
        n--;
    }
    return 0;
}

