root/sys/arch/sh3/sh3/cpu_in_cksum.S
/*      $NetBSD: cpu_in_cksum.S,v 1.12 2024/02/07 04:20:27 msaitoh Exp $        */

/*-
 * Copyright (c) 2000 SHIMIZU Ryo
 * 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.
 */

#ifndef _LOCORE
#define _LOCORE
#endif
#include <machine/endian.h>
#include <machine/asm.h>
#include "assym.h"

__KERNEL_RCSID(0, "$NetBSD: cpu_in_cksum.S,v 1.12 2024/02/07 04:20:27 msaitoh Exp $")


#define reg_byte_swapped        r1
#define reg_mlen                r2
#define reg_tmp3                r3
#define reg_m                   r4
#define reg_len                 r5
#define reg_off                 r6
#define reg_w                   r6      /* recycle */
#define reg_sum                 r7


#define REDUCE  \
        swap.w  reg_sum, r0             ; \
        extu.w  reg_sum, reg_sum        ; \
        extu.w  r0, r0                  ; \
        add     r0, reg_sum

#define ROL     \
        shll8   reg_sum

#if _BYTE_ORDER == BIG_ENDIAN
#define ADDB    \
        mov.b   @reg_w+, r0     ; \
        ROL                     ; \
        extu.b  r0, r0          ; \
        add     r0, reg_sum     ; \
        not     reg_byte_swapped, reg_byte_swapped
#else
#define ADDB    \
        mov.b   @reg_w+, r0     ; \
        extu.b  r0, r0          ; \
        add     r0, reg_sum     ; \
        ROL                     ; \
        not     reg_byte_swapped, reg_byte_swapped
#endif


#define ADDS    \
        mov.w   @reg_w+, r0     ; \
        extu.w  r0, r0          ; \
        add     r0, reg_sum

#define ADDCL   \
        mov.l   @reg_w+, r0     ; \
        addc    r0, reg_sum

#define FORWARD1        \
        add     #-1, reg_mlen

#define FORWARD2        \
        add     #-2, reg_mlen


/*
 * LINTSTUB: include <sys/param.h>
 * LINTSTUB: include <sys/mbuf.h>
 *
 * LINTSTUB: Func: int cpu_in_cksum(struct mbuf *m, int len, int off, uint32_t initial_sum);
 */
ENTRY(cpu_in_cksum)
        sts.l   pr, @-sp
        PIC_PROLOGUE(.L_got)

        tst     reg_len, reg_len
        bt/s    mbuf_loop_done
         mov    #0, reg_byte_swapped

.L_mbuf_skip:
        tst     reg_m, reg_m
        bt      out_of_mbufs

        mov.l   @(M_LEN, reg_m), reg_mlen
        cmp/gt  reg_off, reg_mlen       /* mlen > off ? */
        bt      .L_mbuf_found

        !! while (off >= mlen)
        mov.l   @(M_NEXT, reg_m), reg_m ! m = m->m_next
        bra     .L_mbuf_skip
         sub    reg_mlen, reg_off       ! off -= mlen


.L_mbuf_found: !! if (mlen > off)
        mov.l   @(M_DATA, reg_m), reg_tmp3
        sub     reg_off, reg_mlen       ! mlen -= off
        bra     .L_mbuf_loop_enter
         add    reg_tmp3, reg_off       ! w = m->m_data + off

#undef  reg_off /* it is dead now and we recycle it for reg_w */


mbuf_loop:
        tst     reg_m, reg_m
        bt      out_of_mbufs

        mov.l   @(M_LEN, reg_m), reg_mlen
        tst     reg_mlen, reg_mlen
        bt/s    mbuf_loop_continue
        mov.l   @(M_DATA, reg_m), reg_w


        !! Entry point for mbuf loop.  We jump here after we have
        !! found the mbuf (reg_m) that contains data at the specified
        !! offset.  reg_mlen and reg_w were adjusted to point at the
        !! first interesting byte of data.
.L_mbuf_loop_enter:
        cmp/ge  reg_mlen, reg_len
        bt      1f
        mov     reg_len, reg_mlen
1:
        sub     reg_mlen, reg_len


        mov     reg_w, r0
        tst     #1, r0
        bt/s    1f
        REDUCE          /* 1st instruction break only r0 */
        ADDB
        FORWARD1
1:


        mov     #1, r0
        cmp/gt  r0, reg_mlen
        bf/s    1f
        mov     reg_w, r0
        tst     #2, r0
        bt/s    1f
        REDUCE          /* 1st instruction break only r0 */
        ADDS
        FORWARD2
1:



        mov     #127, r0
        cmp/hi  r0, reg_mlen
        bf      1f

do_cksum128:
        bsr     cksum128
         nop

        mov     #127, r0
        cmp/hi  r0, reg_mlen
        bt      do_cksum128
1:


        bsr     cksum128mod
         nop

        REDUCE

        mov     #1, r0
        cmp/gt  r0, reg_mlen
        bf      1f
        ADDS
        FORWARD2
1:

        mov     reg_mlen, r0
        tst     #1, r0
        bt      1f
        ADDB
1:


mbuf_loop_continue:
        mov.l   @(M_NEXT, reg_m), reg_m

        tst     reg_len, reg_len
        bf/s    mbuf_loop
mbuf_loop_done:


        tst     reg_byte_swapped, reg_byte_swapped
        bt/s    1f
        REDUCE          /* 1st instruction break only r0 */
        ROL
1:

        REDUCE
        REDUCE

in_cksum_return:
        not     reg_sum, r0
        PIC_EPILOGUE
        lds.l   @sp+, pr
        rts
         extu.w r0, r0


out_of_mbufs:
        mova    .L_message_out_of_data, r0
        mov.l   .L_printf, reg_tmp3

        mov.l   reg_sum, @-sp   /* save: call clobbered register */

1:      CALL    reg_tmp3
         mov    r0, r4

        bra     in_cksum_return
         mov.l  @sp+, reg_sum   /* restore */

        .align 2
.L_got:
        PIC_GOT_DATUM
.L_printf:
        CALL_DATUM(_C_LABEL(printf), 1b)

        .align 2        /* mova target */
.L_message_out_of_data:
        .asciz "cksum: out of data (%d byte short)\n"

        SET_ENTRY_SIZE(cpu_in_cksum)


        .align  2
cksum128mod:
        mov     reg_mlen, r0
        and     #124, r0
        sub     r0, reg_mlen
        mov     r0, reg_tmp3

        mova    cksum128_tail, r0
        sub     reg_tmp3, r0
        jmp     @r0
         clrt

        .align  2
cksum128:
        add     #-128, reg_mlen
        clrt

cksum128_unroll:
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
        ADDCL
cksum128_tail:
        mov     #0, r0
        rts
         addc   r0, reg_sum