//******************************************************************************
//*
//* Copyright (C) 2015 The Android Open Source Project
//*
//* Licensed under the Apache License, Version 2.0 (the "License");
//* you may not use this file except in compliance with the License.
//* You may obtain a copy of the License at:
//*
//* http://www.apache.org/licenses/LICENSE-2.0
//*
//* Unless required by applicable law or agreed to in writing, software
//* distributed under the License is distributed on an "AS IS" BASIS,
//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//* See the License for the specific language governing permissions and
//* limitations under the License.
//*
//*****************************************************************************
//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
//*/
//**

///**
//******************************************************************************
//*
//*
//* @brief
//*  This file contains definitions of routines that compute distortion
//*  between two macro/sub blocks of identical dimensions
//*
//* @author
//*  Ittiam
//*
//* @par List of Functions:
//*  - ime_compute_sad_16x16()
//*  - ime_compute_sad_8x8()
//*  - ime_compute_sad_4x4()
//*  - ime_compute_sad_16x8()
//*  - ime_compute_satqd_16x16_lumainter_av8()
//*
//* @remarks
//*  None
//*
//*******************************************************************************
//


///**
//******************************************************************************
//*
//* @brief computes distortion (SAD) between 2 16x16 blocks (fast mode)
//*
//* @par   Description
//*   This functions computes SAD between 2 16x16 blocks. There is a provision
//*   for early exit if the up-to computed SAD exceeds maximum allowed SAD. To
//*   compute the distortion of the entire block set u4_max_sad to USHRT_MAX.
//*
//* @param[in] pu1_src
//*  UWORD8 pointer to the source
//*
//* @param[out] pu1_dst
//*  UWORD8 pointer to the destination
//*
//* @param[in] src_strd
//*  integer source stride
//*
//* @param[in] dst_strd
//*  integer destination stride
//*
//* @param[in] i4_max_sad
//*  integer maximum allowed distortion
//*
//* @param[in] pi4_mb_distortion
//*  integer evaluated sad
//*
//* @remarks
//*
//******************************************************************************
//*/
.text
.p2align 2

.macro push_v_regs
    stp       d8, d9, [sp, #-16]!
    stp       d10, d11, [sp, #-16]!
    stp       d12, d13, [sp, #-16]!
    stp       d14, d15, [sp, #-16]!
.endm
.macro pop_v_regs
    ldp       d14, d15, [sp], #16
    ldp       d12, d13, [sp], #16
    ldp       d10, d11, [sp], #16
    ldp       d8, d9, [sp], #16
.endm

    .global ime_compute_sad_16x16_fast_av8
ime_compute_sad_16x16_fast_av8:
    push_v_regs
    lsl       x2, x2, #1
    lsl       x3, x3, #1

    mov       x6, #2
    movi      v30.8h, #0

core_loop_ime_compute_sad_16x16_fast_av8:

    ld1       {v0.16b}, [x0], x2
    ld1       {v1.16b}, [x1], x3
    ld1       {v2.16b}, [x0], x2
    ld1       {v3.16b}, [x1], x3

    uabal     v30.8h, v0.8b, v1.8b
    uabal2    v30.8h, v0.16b, v1.16b

    uabal     v30.8h, v2.8b, v3.8b
    uabal2    v30.8h, v2.16b, v3.16b

    ld1       {v4.16b}, [x0], x2
    ld1       {v5.16b}, [x1], x3
    ld1       {v6.16b}, [x0], x2
    ld1       {v7.16b}, [x1], x3

    uabal     v30.8h, v4.8b, v5.8b
    uabal2    v30.8h, v4.16b, v5.16b

    uabal     v30.8h, v6.8b, v7.8b
    uabal2    v30.8h, v6.16b, v7.16b

    subs      x6, x6, #1
    bne       core_loop_ime_compute_sad_16x16_fast_av8


    addp      v30.8h, v30.8h, v30.8h
    uaddlp    v30.4s, v30.8h
    addp      v30.2s, v30.2s, v30.2s
    shl       v30.2s, v30.2s, #1

    st1       {v30.s}[0], [x5]
    pop_v_regs
    ret


///**
//******************************************************************************
//*
//*  @brief computes distortion (SAD) between 2 16x8  blocks
//*
//*
//*  @par   Description
//*   This functions computes SAD between 2 16x8 blocks. There is a provision
//*   for early exit if the up-to computed SAD exceeds maximum allowed SAD. To
//*   compute the distortion of the entire block set u4_max_sad to USHRT_MAX.
//*
//* @param[in] pu1_src
//*  UWORD8 pointer to the source
//*
//* @param[out] pu1_dst
//*  UWORD8 pointer to the destination
//*
//* @param[in] src_strd
//*  integer source stride
//*
//* @param[in] dst_strd
//*  integer destination stride
//*
//* @param[in] u4_max_sad
//*  integer maximum allowed distortion
//*
//* @param[in] pi4_mb_distortion
//*  integer evaluated sad
//*
//* @remarks
//*
//******************************************************************************
//*/
//
    .global ime_compute_sad_16x8_av8
ime_compute_sad_16x8_av8:

    //chheck what stride incremtn to use
    //earlier code did not have this lsl
    push_v_regs
    mov       x6, #2
    movi      v30.8h, #0

core_loop_ime_compute_sad_16x8_av8:

    ld1       {v0.16b}, [x0], x2
    ld1       {v1.16b}, [x1], x3
    ld1       {v2.16b}, [x0], x2
    ld1       {v3.16b}, [x1], x3

    uabal     v30.8h, v0.8b, v1.8b
    uabal2    v30.8h, v0.16b, v1.16b

    uabal     v30.8h, v2.8b, v3.8b
    uabal2    v30.8h, v2.16b, v3.16b

    ld1       {v4.16b}, [x0], x2
    ld1       {v5.16b}, [x1], x3
    ld1       {v6.16b}, [x0], x2
    ld1       {v7.16b}, [x1], x3

    uabal     v30.8h, v4.8b, v5.8b
    uabal2    v30.8h, v4.16b, v5.16b

    uabal     v30.8h, v6.8b, v7.8b
    uabal2    v30.8h, v6.16b, v7.16b

    subs      x6, x6, #1
    bne       core_loop_ime_compute_sad_16x8_av8


    addp      v30.8h, v30.8h, v30.8h
    uaddlp    v30.4s, v30.8h
    addp      v30.2s, v30.2s, v30.2s

    st1       {v30.s}[0], [x5]
    pop_v_regs
    ret

///**
//******************************************************************************
//*
//* @brief computes distortion (SAD) between 2 16x16 blocks with early exit
//*
//* @par   Description
//*   This functions computes SAD between 2 16x16 blocks. There is a provision
//*   for early exit if the up-to computed SAD exceeds maximum allowed SAD. To
//*   compute the distortion of the entire block set u4_max_sad to USHRT_MAX.
//*
//* @param[in] pu1_src
//*  UWORD8 pointer to the source
//*
//* @param[out] pu1_dst
//*  UWORD8 pointer to the destination
//*
//* @param[in] src_strd
//*  integer source stride
//*
//* @param[in] dst_strd
//*  integer destination stride
//*
//* @param[in] i4_max_sad
//*  integer maximum allowed distortion
//*
//* @param[in] pi4_mb_distortion
//*  integer evaluated sad
//*
//* @remarks
//*
//******************************************************************************
//*/

    .global ime_compute_sad_16x16_ea8_av8
ime_compute_sad_16x16_ea8_av8:

    push_v_regs
    movi      v30.8h, #0

    add       x7, x0, x2
    add       x8, x1, x3

    lsl       x2, x2, #1
    lsl       x3, x3, #1

    ld1       {v0.16b}, [x0], x2
    ld1       {v1.16b}, [x1], x3
    ld1       {v2.16b}, [x0], x2
    ld1       {v3.16b}, [x1], x3
    ld1       {v8.16b}, [x0], x2
    ld1       {v9.16b}, [x1], x3
    ld1       {v10.16b}, [x0], x2
    ld1       {v11.16b}, [x1], x3
    ld1       {v12.16b}, [x0], x2
    ld1       {v13.16b}, [x1], x3
    ld1       {v14.16b}, [x0], x2
    ld1       {v15.16b}, [x1], x3
    ld1       {v16.16b}, [x0], x2
    ld1       {v17.16b}, [x1], x3
    ld1       {v18.16b}, [x0], x2
    ld1       {v19.16b}, [x1], x3

    uabal     v30.8h, v0.8b, v1.8b
    uabal2    v30.8h, v0.16b, v1.16b

    uabal     v30.8h, v2.8b, v3.8b
    uabal2    v30.8h, v2.16b, v3.16b

    uabal     v30.8h, v8.8b, v9.8b
    uabal2    v30.8h, v8.16b, v9.16b

    uabal     v30.8h, v10.8b, v11.8b
    uabal2    v30.8h, v10.16b, v11.16b

    uabal     v30.8h, v12.8b, v13.8b
    uabal2    v30.8h, v12.16b, v13.16b

    uabal     v30.8h, v14.8b, v15.8b
    uabal2    v30.8h, v14.16b, v15.16b

    uabal     v30.8h, v16.8b, v17.8b
    uabal2    v30.8h, v16.16b, v17.16b

    uabal     v30.8h, v18.8b, v19.8b
    uabal2    v30.8h, v18.16b, v19.16b

    addp      v31.8h, v30.8h, v30.8h
    uaddlp    v31.4s, v31.8h
    addp      v31.2s, v31.2s, v31.2s
    mov       w6, v31.s[0]
    cmp       w6, w4
    bgt       end_func_16x16

    //do the stuff again
    ld1       {v0.16b}, [x7], x2
    ld1       {v1.16b}, [x8], x3
    ld1       {v2.16b}, [x7], x2
    ld1       {v3.16b}, [x8], x3
    ld1       {v8.16b}, [x7], x2
    ld1       {v9.16b}, [x8], x3
    ld1       {v10.16b}, [x7], x2
    ld1       {v11.16b}, [x8], x3
    ld1       {v12.16b}, [x7], x2
    ld1       {v13.16b}, [x8], x3
    ld1       {v14.16b}, [x7], x2
    ld1       {v15.16b}, [x8], x3
    ld1       {v16.16b}, [x7], x2
    ld1       {v17.16b}, [x8], x3
    ld1       {v18.16b}, [x7], x2
    ld1       {v19.16b}, [x8], x3

    uabal     v30.8h, v0.8b, v1.8b
    uabal2    v30.8h, v0.16b, v1.16b

    uabal     v30.8h, v2.8b, v3.8b
    uabal2    v30.8h, v2.16b, v3.16b

    uabal     v30.8h, v8.8b, v9.8b
    uabal2    v30.8h, v8.16b, v9.16b

    uabal     v30.8h, v10.8b, v11.8b
    uabal2    v30.8h, v10.16b, v11.16b

    uabal     v30.8h, v12.8b, v13.8b
    uabal2    v30.8h, v12.16b, v13.16b

    uabal     v30.8h, v14.8b, v15.8b
    uabal2    v30.8h, v14.16b, v15.16b

    uabal     v30.8h, v16.8b, v17.8b
    uabal2    v30.8h, v16.16b, v17.16b

    uabal     v30.8h, v18.8b, v19.8b
    uabal2    v30.8h, v18.16b, v19.16b

    addp      v31.8h, v30.8h, v30.8h
    uaddlp    v31.4s, v31.8h
    addp      v31.2s, v31.2s, v31.2s

end_func_16x16:
    st1       {v31.s}[0], [x5]
    pop_v_regs
    ret


///*
////---------------------------------------------------------------------------
//// Function Name      : ime_calculate_sad2_prog_av8()
////
//// Detail Description : This function find the sad values of 4 Progressive MBs
////                        at one shot
////
//// Platform           : CortexAv8/NEON            .
////
////-----------------------------------------------------------------------------
//*/

    .global ime_calculate_sad2_prog_av8
ime_calculate_sad2_prog_av8:

    // x0    = ref1     <UWORD8 *>
    // x1    = ref2     <UWORD8 *>
    // x2    = src     <UWORD8 *>
    // x3    = RefBufferWidth <UWORD32>
    // stack = CurBufferWidth <UWORD32>, psad <UWORD32 *>
    push_v_regs
    mov       x6, #8
    movi      v30.8h, #0
    movi      v31.8h, #0

core_loop_ime_calculate_sad2_prog_av8:

    ld1       {v0.16b}, [x0], x3
    ld1       {v1.16b}, [x1], x3
    ld1       {v2.16b}, [x3], x4

    ld1       {v3.16b}, [x0], x3
    ld1       {v4.16b}, [x1], x3
    ld1       {v5.16b}, [x3], x4


    uabal     v30.8h, v0.8b, v2.8b
    uabal2    v30.8h, v0.16b, v2.16b
    uabal     v31.8h, v1.8b, v2.8b
    uabal2    v31.8h, v1.16b, v2.16b

    uabal     v30.8h, v3.8b, v5.8b
    uabal2    v30.8h, v3.16b, v5.16b
    uabal     v31.8h, v4.8b, v5.8b
    uabal2    v31.8h, v4.16b, v5.16b


    ld1       {v6.16b}, [x0], x3
    ld1       {v7.16b}, [x1], x3
    ld1       {v8.16b}, [x3], x4

    ld1       {v9.16b}, [x0], x3
    ld1       {v10.16b}, [x1], x3
    ld1       {v11.16b}, [x3], x4

    uabal     v30.8h, v6.8b, v8.8b
    uabal2    v30.8h, v6.16b, v8.16b
    uabal     v31.8h, v7.8b, v8.8b
    uabal2    v31.8h, v7.16b, v8.16b

    uabal     v30.8h, v9.8b, v11.8b
    uabal2    v30.8h, v9.16b, v11.16b
    uabal     v31.8h, v10.8b, v11.8b
    uabal2    v31.8h, v0.16b, v11.16b

    subs      x6, x6, #1
    bne       core_loop_ime_calculate_sad2_prog_av8

    addp      v30.8h, v30.8h, v31.8h
    uaddlp    v30.4s, v30.8h
    addp      v30.2s, v30.2s, v30.2s
    shl       v30.2s, v30.2s, #1

    st1       {v30.2s}, [x5]
    pop_v_regs
    ret

///*
////---------------------------------------------------------------------------
//// Function Name      : Calculate_Mad3_prog()
////
//// Detail Description : This function find the sad values of 4 Progressive MBs
////                        at one shot
////
//// Platform           : CortexA8/NEON            .
////
////-----------------------------------------------------------------------------
//*/

    .global ime_calculate_sad3_prog_av8
ime_calculate_sad3_prog_av8:

    // x0    = ref1     <UWORD8 *>
    // x1    = ref2     <UWORD8 *>
    // x2    = ref3     <UWORD8 *>
    // x3    = src     <UWORD8 *>
    // stack = RefBufferWidth <UWORD32>, CurBufferWidth <UWORD32>, psad <UWORD32 *>


    // x0    = ref1     <UWORD8 *>
    // x1    = ref2     <UWORD8 *>
    // x2    = src     <UWORD8 *>
    // x3    = RefBufferWidth <UWORD32>
    // stack = CurBufferWidth <UWORD32>, psad <UWORD32 *>
    push_v_regs
    mov       x6, #16
    movi      v29.8h, #0
    movi      v30.8h, #0
    movi      v31.8h, #0

core_loop_ime_calculate_sad3_prog_av8:

    ld1       {v0.16b}, [x0], x4
    ld1       {v1.16b}, [x1], x4
    ld1       {v2.16b}, [x2], x4
    ld1       {v3.16b}, [x3], x5

    uabal     v29.8h, v0.8b, v3.8b
    uabal2    v29.8h, v0.16b, v3.16b
    uabal     v30.8h, v1.8b, v3.8b
    uabal2    v30.8h, v1.16b, v3.16b
    uabal     v31.8h, v2.8b, v3.8b
    uabal2    v31.8h, v2.16b, v3.16b

    ld1       {v4.16b}, [x0], x4
    ld1       {v5.16b}, [x1], x4
    ld1       {v6.16b}, [x2], x4
    ld1       {v7.16b}, [x3], x5

    uabal     v29.8h, v4.8b, v7.8b
    uabal2    v29.8h, v4.16b, v7.16b
    uabal     v30.8h, v5.8b, v7.8b
    uabal2    v30.8h, v5.16b, v7.16b
    uabal     v31.8h, v6.8b, v7.8b
    uabal2    v31.8h, v6.16b, v7.16b

    subs      x6, x6, #1
    bne       core_loop_ime_calculate_sad2_prog_av8

    addp      v30.8h, v30.8h, v31.8h
    uaddlp    v30.4s, v30.8h
    addp      v30.2s, v30.2s, v30.2s
    shl       v30.2s, v30.2s, #1

    st1       {v30.2s}, [x5]
    pop_v_regs
    ret




///**
//******************************************************************************
//*
//* @brief computes distortion (SAD) for sub-pel motion estimation
//*
//* @par   Description
//*   This functions computes SAD for all the 8 half pel points
//*
//* @param[out] pi4_sad
//*  integer evaluated sad
//*  pi4_sad[0] - half x
//*  pi4_sad[1] - half x - 1
//*  pi4_sad[2] - half y
//*  pi4_sad[3] - half y - 1
//*  pi4_sad[4] - half xy
//*  pi4_sad[5] - half xy - 1
//*  pi4_sad[6] - half xy - strd
//*  pi4_sad[7] - half xy - 1 - strd
//*
//* @remarks
//*
//******************************************************************************
//*/

.text
.p2align 2

    .global ime_sub_pel_compute_sad_16x16_av8
ime_sub_pel_compute_sad_16x16_av8:
    push_v_regs
    sub       x7, x1, #1                //x left
    sub       x8, x2, x5                //y top
    sub       x9, x3, #1                //xy  left
    sub       x10, x3, x5               //xy top
    sub       x11, x10, #1              //xy top left

    movi      v24.8h, #0
    movi      v25.8h, #0
    movi      v26.8h, #0
    movi      v27.8h, #0
    movi      v28.8h, #0
    movi      v29.8h, #0
    movi      v30.8h, #0
    movi      v31.8h, #0

    mov       x12, #16
core_loop_ime_sub_pel_compute_sad_16x16_av8:

    ld1       {v0.16b}, [x0], x4        //src
    ld1       {v1.16b}, [x1], x5        //x
    ld1       {v2.16b}, [x7], x5        //x left
    ld1       {v3.16b}, [x2], x5        //y
    ld1       {v9.16b}, [x8], x5        //y top
    ld1       {v10.16b}, [x3], x5       //xy
    ld1       {v11.16b}, [x9], x5       //xy left
    ld1       {v12.16b}, [x10], x5      //xy top
    ld1       {v13.16b}, [x11], x5      //xy top left

    uabal     v24.8h, v0.8b, v1.8b
    uabal2    v24.8h, v0.16b, v1.16b
    uabal     v25.8h, v0.8b, v2.8b
    uabal2    v25.8h, v0.16b, v2.16b
    uabal     v26.8h, v0.8b, v3.8b
    uabal2    v26.8h, v0.16b, v3.16b
    uabal     v27.8h, v0.8b, v9.8b
    uabal2    v27.8h, v0.16b, v9.16b
    uabal     v28.8h, v0.8b, v10.8b
    uabal2    v28.8h, v0.16b, v10.16b
    uabal     v29.8h, v0.8b, v11.8b
    uabal2    v29.8h, v0.16b, v11.16b
    uabal     v30.8h, v0.8b, v12.8b
    uabal2    v30.8h, v0.16b, v12.16b
    uabal     v31.8h, v0.8b, v13.8b
    uabal2    v31.8h, v0.16b, v13.16b

    subs      x12, x12, #1
    bne       core_loop_ime_sub_pel_compute_sad_16x16_av8

    addp      v24.8h, v24.8h, v25.8h
    addp      v26.8h, v26.8h, v27.8h
    addp      v28.8h, v28.8h, v29.8h
    addp      v30.8h, v30.8h, v31.8h

    uaddlp    v24.4s, v24.8h
    uaddlp    v26.4s, v26.8h
    uaddlp    v28.4s, v28.8h
    uaddlp    v30.4s, v30.8h

    addp      v24.4s, v24.4s, v26.4s
    addp      v25.4s, v28.4s, v30.4s

    st1       {v24.4s-v25.4s}, [x6]


    pop_v_regs
    ret


///**
//******************************************************************************
//*
//* @brief computes distortion (SAD) between 2 16x16 blocks
//*
//* @par   Description
//*   This functions computes SAD between 2 16x16 blocks. There is a provision
//*   for early exit if the up-to computed SAD exceeds maximum allowed SAD. To
//*   compute the distortion of the entire block set u4_max_sad to USHRT_MAX.
//*
//* @param[in] pu1_src
//*  UWORD8 pointer to the source
//*
//* @param[out] pu1_dst
//*  UWORD8 pointer to the destination
//*
//* @param[in] src_strd
//*  integer source stride
//*
//* @param[in] dst_strd
//*  integer destination stride
//*
//* @param[in] i4_max_sad
//*  integer maximum allowed distortion
//*
//* @param[in] pi4_mb_distortion
//*  integer evaluated sad
//*
//* @remarks
//*
//******************************************************************************
//*/
    .global ime_compute_sad_16x16_av8
ime_compute_sad_16x16_av8:
    push_v_regs
    mov       x6, #4
    movi      v30.8h, #0

core_loop_ime_compute_sad_16x16_av8:

    ld1       {v0.16b}, [x0], x2
    ld1       {v1.16b}, [x1], x3
    ld1       {v2.16b}, [x0], x2
    ld1       {v3.16b}, [x1], x3

    uabal     v30.8h, v0.8b, v1.8b
    uabal2    v30.8h, v0.16b, v1.16b

    uabal     v30.8h, v2.8b, v3.8b
    uabal2    v30.8h, v2.16b, v3.16b

    ld1       {v4.16b}, [x0], x2
    ld1       {v5.16b}, [x1], x3
    ld1       {v6.16b}, [x0], x2
    ld1       {v7.16b}, [x1], x3

    uabal     v30.8h, v4.8b, v5.8b
    uabal2    v30.8h, v4.16b, v5.16b

    uabal     v30.8h, v6.8b, v7.8b
    uabal2    v30.8h, v6.16b, v7.16b

    subs      x6, x6, #1
    bne       core_loop_ime_compute_sad_16x16_av8


    addp      v30.8h, v30.8h, v30.8h
    uaddlp    v30.4s, v30.8h
    addp      v30.2s, v30.2s, v30.2s

    st1       {v30.s}[0], [x5]
    pop_v_regs
    ret


///*
////---------------------------------------------------------------------------
//// Function Name      : Calculate_Mad4_prog()
////
//// Detail Description : This function find the sad values of 4 Progressive MBs
////                        at one shot
////
//// Platform           : CortexA8/NEON            .
////
////-----------------------------------------------------------------------------
//*/

    .global ime_calculate_sad4_prog_av8
ime_calculate_sad4_prog_av8:
    push_v_regs
    sub       x5, x0, #1                //left
    add       x6, x0, #1                //right
    sub       x7, x0, x2                //top
    add       x8, x0, x2                //bottom

    movi      v28.8h, #0
    movi      v29.8h, #0
    movi      v30.8h, #0
    movi      v31.8h, #0

    mov       x9, #16
core_loop_ime_calculate_sad4_prog_av8:

    ld1       {v0.16b}, [x1], x3
    ld1       {v1.16b}, [x5], x2
    ld1       {v2.16b}, [x6], x2
    ld1       {v3.16b}, [x7], x2
    ld1       {v9.16b}, [x8], x2

    uabal     v28.8h, v0.8b, v1.8b
    uabal2    v28.8h, v0.16b, v1.16b
    uabal     v29.8h, v0.8b, v2.8b
    uabal2    v29.8h, v0.16b, v2.16b
    uabal     v30.8h, v0.8b, v3.8b
    uabal2    v30.8h, v0.16b, v3.16b
    uabal     v31.8h, v0.8b, v9.8b
    uabal2    v31.8h, v0.16b, v9.16b

    subs      x9, x9, #1
    bne       core_loop_ime_calculate_sad4_prog_av8

    addp      v28.8h, v28.8h, v29.8h
    addp      v30.8h, v30.8h, v31.8h

    uaddlp    v28.4s, v28.8h
    uaddlp    v30.4s, v30.8h

    addp      v28.4s, v28.4s, v30.4s
    st1       {v28.4s}, [x4]
    pop_v_regs
    ret



//*****************************************************************************
//*
//* Function Name         : ime_compute_satqd_16x16_lumainter_av8
//* Description           : This fucntion computes SAD for a 16x16 block.
//                        : It also computes if any 4x4 block will have a nonzero coefficent after transform and quant
//
//  Arguments             :   x0 :pointer to src buffer
//                            x1 :pointer to est buffer
//                            x2 :source stride
//                            x3 :est stride
//                            STACk :Threshold,distotion,is_nonzero
//*
//* Values Returned   : NONE
//*
//* Register Usage    : x0-x11
//* Stack Usage       :
//* Cycles            : Around
//* Interruptiaility  : Interruptable
//*
//* Known Limitations
//*   \Assumptions    :
//*
//* Revision History  :
//*         DD MM YYYY    Author(s)           Changes
//*         14 04 2014    Harinarayanan K K  First version
//*
//*****************************************************************************
    .global ime_compute_satqd_16x16_lumainter_av8
ime_compute_satqd_16x16_lumainter_av8:
    //x0 :pointer to src buffer
    //x1 :pointer to est buffer
    //x2 :Source stride
    //x3 :Pred stride
    //x4 :Threshold pointer
    //x5 :Distortion,ie SAD
    //x6 :is nonzero
    //x7 :loop counter
    push_v_regs
    stp       d8, d9, [sp, #-16]!
    stp       d10, d11, [sp, #-16]!
    stp       d12, d13, [sp, #-16]!
    stp       d14, d15, [sp, #-16]!

    ld1       {v30.8h}, [x4]

    dup       v20.4h, v30.h[1]          //ls1
    dup       v24.4h, v30.h[0]          //ls2
    dup       v21.4h, v30.h[5]          //ls3
    dup       v25.4h, v30.h[7]          //ls4
    dup       v22.4h, v30.h[3]          //ls5
    dup       v26.4h, v30.h[4]          //ls6
    dup       v23.4h, v30.h[6]          //ls7
    dup       v27.4h, v30.h[2]          //ls8

    mov       v20.d[1], v24.d[0]
    mov       v21.d[1], v25.d[0]
    mov       v22.d[1], v26.d[0]
    mov       v23.d[1], v27.d[0]

    add       x4, x4, #16
    ld1       {v29.h}[0], [x4]
    dup       v29.4h, v29.h[0]

    movi      v31.8h, #0

    mov       x7, #4
core_loop_satqd_ime_compute_satqd_16x16_lumainter:
    ld1       {v0.16b}, [x0], x2
    ld1       {v1.16b}, [x1], x3
    ld1       {v2.16b}, [x0], x2
    ld1       {v3.16b}, [x1], x3
    ld1       {v4.16b}, [x0], x2
    ld1       {v5.16b}, [x1], x3
    ld1       {v6.16b}, [x0], x2
    ld1       {v7.16b}, [x1], x3

    uabdl     v10.8h, v0.8b, v1.8b
    uabdl2    v15.8h, v0.16b, v1.16b
    uabdl     v11.8h, v2.8b, v3.8b
    uabdl2    v16.8h, v2.16b, v3.16b
    uabdl     v12.8h, v4.8b, v5.8b
    uabdl2    v17.8h, v4.16b, v5.16b
    uabdl     v13.8h, v6.8b, v7.8b
    uabdl2    v18.8h, v6.16b, v7.16b

    add       v0.8h, v10.8h, v13.8h
    add       v1.8h, v11.8h, v12.8h
    add       v2.8h, v15.8h, v18.8h
    add       v3.8h, v16.8h, v17.8h

    //v0 : S1     S4     S4     S1        A1    A4    A4    A1
    //v1 : S2     S3     S3     S2        A2    A3    A3    A2
    //v2 : B1     B4     B4     B1        X1    X4    X4    X1
    //v3 : B3     B2     B2     B3        X3    X2    X2    X3

    trn1      v4.8h, v0.8h, v1.8h
    trn2      v5.8h, v0.8h, v1.8h
    trn1      v6.8h, v2.8h, v3.8h
    trn2      v7.8h, v2.8h, v3.8h

    trn1      v0.4s, v4.4s, v6.4s
    trn2      v2.4s, v4.4s, v6.4s
    trn1      v1.4s, v5.4s, v7.4s
    trn2      v3.4s, v5.4s, v7.4s

    add       v4.8h, v0.8h, v3.8h
    add       v5.8h, v1.8h, v2.8h
    //v4 : S1     S2     B1     B2      A1    A2    X1    X2
    //v5 : S4     S3     B4     B3      A4    A3    X4    X3

    //compute sad for each 4x4 block
    add       v6.8h, v4.8h, v5.8h
    addp      v19.8h, v6.8h, v6.8h
    //duplicate the sad into 128 bit so that we can compare using 128bit
    add       v31.4h, v31.4h, v19.4h

    //sad_2 = sad_1<<1;
    shl       v28.8h, v19.8h, #1

    //sad_2 - pu2_thrsh
    sub       v24.8h, v28.8h, v20.8h
    sub       v25.8h, v28.8h, v21.8h
    sub       v26.8h, v28.8h, v22.8h
    sub       v27.8h, v28.8h, v23.8h

    trn1      v0.4s, v4.4s, v5.4s
    trn2      v1.4s, v4.4s, v5.4s
    //v0 : S1     S2     S4     S3      A1    A2    A4    A3
    //v1 : B1     B2     B4     B3      X1    X2    X4    X3

    trn1      v4.8h, v0.8h, v1.8h
    trn2      v5.8h, v0.8h, v1.8h
    //v4 : S1     B1     S4     B4      A1    X1    A4    X4
    //v5 : S2     B2     S3     B3      A2    X2    A3    X3

    mov       v7.s[0], v4.s[1]
    mov       v7.s[1], v4.s[3]
    mov       v6.s[0], v5.s[1]          // V4 //S1 B1 A1 X1
    mov       v6.s[1], v5.s[3]          // V5 //S2 B2 A2 X2
    mov       v4.s[1], v4.s[2]          // V6 //S3 B3 A3 X3
    mov       v5.s[1], v5.s[2]          // V7 //S4 B4 A4 X4

    shl       v0.4h, v4.4h, #1          //S1<<1
    shl       v1.4h, v5.4h, #1          //S2<<1
    shl       v2.4h, v6.4h, #1          //S3<<1
    shl       v3.4h, v7.4h, #1          //S4<<1

    add       v8.4h, v5.4h, v6.4h       //(s2[j] + s3[j]))
    add       v9.4h, v4.4h, v7.4h       //(s1[j] + s4[j]))
    add       v10.4h, v6.4h, v7.4h      //(s3[j] + s4[j]))
    sub       v11.4h, v6.4h, v0.4h      //(s3[j] - (s1[j]<<1))
    sub       v12.4h, v7.4h, v1.4h      //(s4[j] - (s2[j]<<1))
    add       v13.4h, v4.4h, v5.4h      //(s1[j] + s2[j]))
    sub       v14.4h, v5.4h, v3.4h      //(s2[j] - (s4[j]<<1)))
    sub       v15.4h, v4.4h, v2.4h      //(s1[j] - (s3[j]<<1)))

    mov       v8.d[1], v9.d[0]
    mov       v10.d[1], v11.d[0]
    mov       v12.d[1], v13.d[0]
    mov       v14.d[1], v15.d[0]

    cmge      v0.8h, v24.8h, v8.8h      //ls1 ls2
    cmge      v1.8h, v25.8h, v10.8h     //ls3 ls4
    cmge      v2.8h, v26.8h, v12.8h     //ls5 ls6
    cmge      v3.8h, v27.8h, v14.8h     //ls7 ls8
    cmge      v4.4h, v19.4h, v29.4h     //sad

    orr       v0.16b, v0.16b, v1.16b
    orr       v2.16b, v2.16b, v3.16b
    orr       v2.16b, v0.16b, v2.16b
    xtn       v2.8b, v2.8h
    orr       v2.8b, v2.8b, v4.8b

    //if the comparison is non zero, out
    mov       x4, v2.d[0]
    cmp       x4, #0
    bne       core_loop_compute_sad_pre

    subs      x7, x7, #1
    bne       core_loop_satqd_ime_compute_satqd_16x16_lumainter
    b         satdq_end_func


core_loop_compute_sad:
    ld1       {v0.16b}, [x0], x2
    ld1       {v1.16b}, [x1], x3
    ld1       {v2.16b}, [x0], x2
    ld1       {v3.16b}, [x1], x3

    uabal     v31.8h, v0.8b, v1.8b
    uabal2    v31.8h, v0.16b, v1.16b

    uabal     v31.8h, v2.8b, v3.8b
    uabal2    v31.8h, v2.16b, v3.16b

    ld1       {v4.16b}, [x0], x2
    ld1       {v5.16b}, [x1], x3
    ld1       {v6.16b}, [x0], x2
    ld1       {v7.16b}, [x1], x3

    uabal     v31.8h, v4.8b, v5.8b
    uabal2    v31.8h, v4.16b, v5.16b

    uabal     v31.8h, v6.8b, v7.8b
    uabal2    v31.8h, v6.16b, v7.16b

core_loop_compute_sad_pre:
    subs      x7, x7, #1
    bne       core_loop_compute_sad

satdq_end_func:

    mov       x7, #1
    cmp       x4, #0
    csel      x7, x4, x7, eq
    str       w7, [x6]

    addp      v31.8h, v31.8h, v31.8h
    uaddlp    v31.4s, v31.8h
    addp      v31.2s, v31.2s, v31.2s
    st1       {v31.s}[0], [x5]


    ldp       d14, d15, [sp], #16
    ldp       d12, d13, [sp], #16
    ldp       d10, d11, [sp], #16
    ldp       d8, d9, [sp], #16
    pop_v_regs
    ret