;*!
;* \copy
;*     Copyright (c)  2009-2013, Cisco Systems
;*     All rights reserved.
;*
;*     Redistribution and use in source and binary forms, with or without
;*     modification, are permitted provided that the following conditions
;*     are met:
;*
;*        * Redistributions of source code must retain the above copyright
;*          notice, this list of conditions and the following disclaimer.
;*
;*        * 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.
;*
;*     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;*     "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
;*     COPYRIGHT HOLDER 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.
;*
;*
;*  mb_copy.asm
;*
;*  Abstract
;*      mb_copy and mb_copy1
;*
;*  History
;*      15/09/2009 Created
;*		12/28/2009 Modified with larger throughput
;*		12/29/2011 Tuned WelsCopy16x16NotAligned_sse2, added UpdateMbMv_sse2 WelsCopy16x8NotAligned_sse2,
;*				   WelsCopy16x8_mmx, WelsCopy8x16_mmx etc;
;*
;*
;*********************************************************************************************/
%include "asm_inc.asm"

;***********************************************************************
; Macros and other preprocessor constants
;***********************************************************************

;***********************************************************************
; Code
;***********************************************************************

SECTION .text

WELS_EXTERN WelsCopy16x16_sse2
WELS_EXTERN WelsCopy16x16NotAligned_sse2
WELS_EXTERN WelsCopy8x8_mmx
WELS_EXTERN WelsCopy16x8NotAligned_sse2	;
WELS_EXTERN WelsCopy8x16_mmx		;
WELS_EXTERN UpdateMbMv_sse2		;

;***********************************************************************
; void WelsCopy16x16_sse2(	uint8_t* Dst,
;							int32_t  iStrideD,
;							uint8_t* Src,
;							int32_t  iStrideS )
;***********************************************************************
ALIGN 16
WelsCopy16x16_sse2:

	push r4
	push r5
	%assign  push_num 2
    LOAD_4_PARA

	lea r4, [r1+2*r1]	;ebx, [eax+2*eax]	; x3
	lea r5, [r3+2*r3]	;edx, [ecx+2*ecx]	; x3

	movdqa xmm0, [r2]
	movdqa xmm1, [r2+r3]
	movdqa xmm2, [r2+2*r3]
	movdqa xmm3, [r2+r5]
	lea r2, [r2+4*r3]
	movdqa xmm4, [r2]
	movdqa xmm5, [r2+r3]
	movdqa xmm6, [r2+2*r3]
	movdqa xmm7, [r2+r5]
	lea r2, [r2+4*r3]

	movdqa [r0], xmm0
	movdqa [r0+r1], xmm1
	movdqa [r0+2*r1], xmm2
	movdqa [r0+r4], xmm3
	lea r0, [r0+4*r1]
	movdqa [r0], xmm4
	movdqa [r0+r1], xmm5
	movdqa [r0+2*r1], xmm6
	movdqa [r0+r4], xmm7
	lea r0, [r0+4*r1]

	movdqa xmm0, [r2]
	movdqa xmm1, [r2+r3]
	movdqa xmm2, [r2+2*r3]
	movdqa xmm3, [r2+r5]
	lea r2, [r2+4*r3]
	movdqa xmm4, [r2]
	movdqa xmm5, [r2+r3]
	movdqa xmm6, [r2+2*r3]
	movdqa xmm7, [r2+r5]

	movdqa [r0], xmm0
	movdqa [r0+r1], xmm1
	movdqa [r0+2*r1], xmm2
	movdqa [r0+r4], xmm3
	lea r0, [r0+4*r1]
	movdqa [r0], xmm4
	movdqa [r0+r1], xmm5
	movdqa [r0+2*r1], xmm6
	movdqa [r0+r4], xmm7
	LOAD_4_PARA_POP
	pop r5
	pop r4
	ret

;***********************************************************************
; void WelsCopy16x16NotAligned_sse2(	uint8_t* Dst,
;							int32_t  iStrideD,
;							uint8_t* Src,
;							int32_t  iStrideS )
;***********************************************************************
ALIGN 16
; dst can be align with 16 bytes, but not sure about pSrc, 12/29/2011
WelsCopy16x16NotAligned_sse2:
	;push esi
	;push edi
	;push ebx

	;mov edi, [esp+16]	; Dst
	;mov eax, [esp+20]	; iStrideD
	;mov esi, [esp+24]	; Src
	;mov ecx, [esp+28]	; iStrideS

	push r4
	push r5
	%assign  push_num 2
    LOAD_4_PARA

	lea r4, [r1+2*r1]	;ebx, [eax+2*eax]	; x3
	lea r5, [r3+2*r3]	;edx, [ecx+2*ecx]	; x3

	movdqu xmm0, [r2]
	movdqu xmm1, [r2+r3]
	movdqu xmm2, [r2+2*r3]
	movdqu xmm3, [r2+r5]
	lea r2, [r2+4*r3]
	movdqu xmm4, [r2]
	movdqu xmm5, [r2+r3]
	movdqu xmm6, [r2+2*r3]
	movdqu xmm7, [r2+r5]
	lea r2, [r2+4*r3]

	movdqa [r0], xmm0
	movdqa [r0+r1], xmm1
	movdqa [r0+2*r1], xmm2
	movdqa [r0+r4], xmm3
	lea r0, [r0+4*r1]
	movdqa [r0], xmm4
	movdqa [r0+r1], xmm5
	movdqa [r0+2*r1], xmm6
	movdqa [r0+r4], xmm7
	lea r0, [r0+4*r1]

	movdqu xmm0, [r2]
	movdqu xmm1, [r2+r3]
	movdqu xmm2, [r2+2*r3]
	movdqu xmm3, [r2+r5]
	lea r2, [r2+4*r3]
	movdqu xmm4, [r2]
	movdqu xmm5, [r2+r3]
	movdqu xmm6, [r2+2*r3]
	movdqu xmm7, [r2+r5]

	movdqa [r0], xmm0
	movdqa [r0+r1], xmm1
	movdqa [r0+2*r1], xmm2
	movdqa [r0+r4], xmm3
	lea r0, [r0+4*r1]
	movdqa [r0], xmm4
	movdqa [r0+r1], xmm5
	movdqa [r0+2*r1], xmm6
	movdqa [r0+r4], xmm7
	LOAD_4_PARA_POP
	pop r5
	pop r4
	ret

; , 12/29/2011
;***********************************************************************
; void WelsCopy16x8NotAligned_sse2(uint8_t* Dst,
;							int32_t  iStrideD,
;							uint8_t* Src,
;							int32_t  iStrideS )
;***********************************************************************
ALIGN 16
WelsCopy16x8NotAligned_sse2:
	;push esi
	;push edi
	;push ebx

	;mov edi, [esp+16]	; Dst
	;mov eax, [esp+20]	; iStrideD
	;mov esi, [esp+24]	; Src
	;mov ecx, [esp+28]	; iStrideS

	push r4
	push r5
	%assign  push_num 2
    LOAD_4_PARA

	lea r4, [r1+2*r1]	;ebx, [eax+2*eax]	; x3
	lea r5, [r3+2*r3]	;edx, [ecx+2*ecx]	; x3

	movdqu xmm0, [r2]
	movdqu xmm1, [r2+r3]
	movdqu xmm2, [r2+2*r3]
	movdqu xmm3, [r2+r5]
	lea r2, [r2+4*r3]
	movdqu xmm4, [r2]
	movdqu xmm5, [r2+r3]
	movdqu xmm6, [r2+2*r3]
	movdqu xmm7, [r2+r5]

	movdqa [r0], xmm0
	movdqa [r0+r1], xmm1
	movdqa [r0+2*r1], xmm2
	movdqa [r0+r4], xmm3
	lea r0, [r0+4*r1]
	movdqa [r0], xmm4
	movdqa [r0+r1], xmm5
	movdqa [r0+2*r1], xmm6
	movdqa [r0+r4], xmm7
	LOAD_4_PARA_POP
	pop r5
	pop r4
	ret


;***********************************************************************
; void WelsCopy8x16_mmx(uint8_t* Dst,
;                       int32_t  iStrideD,
;                       uint8_t* Src,
;                       int32_t  iStrideS )
;***********************************************************************
ALIGN 16
WelsCopy8x16_mmx:
	;push ebx

	;mov eax, [esp + 8 ]           ;Dst
	;mov ecx, [esp + 12]           ;iStrideD
	;mov ebx, [esp + 16]           ;Src
	;mov edx, [esp + 20]           ;iStrideS

	%assign  push_num 0
    LOAD_4_PARA

	movq mm0, [r2]
	movq mm1, [r2+r3]
	lea r2, [r2+2*r3]
	movq mm2, [r2]
	movq mm3, [r2+r3]
	lea r2, [r2+2*r3]
	movq mm4, [r2]
	movq mm5, [r2+r3]
	lea r2, [r2+2*r3]
	movq mm6, [r2]
	movq mm7, [r2+r3]
	lea r2, [r2+2*r3]

	movq [r0], mm0
	movq [r0+r1], mm1
	lea r0, [r0+2*r1]
	movq [r0], mm2
	movq [r0+r1], mm3
	lea r0, [r0+2*r1]
	movq [r0], mm4
	movq [r0+r1], mm5
	lea r0, [r0+2*r1]
	movq [r0], mm6
	movq [r0+r1], mm7
	lea r0, [r0+2*r1]

	movq mm0, [r2]
	movq mm1, [r2+r3]
	lea r2, [r2+2*r3]
	movq mm2, [r2]
	movq mm3, [r2+r3]
	lea r2, [r2+2*r3]
	movq mm4, [r2]
	movq mm5, [r2+r3]
	lea r2, [r2+2*r3]
	movq mm6, [r2]
	movq mm7, [r2+r3]

	movq [r0], mm0
	movq [r0+r1], mm1
	lea r0, [r0+2*r1]
	movq [r0], mm2
	movq [r0+r1], mm3
	lea r0, [r0+2*r1]
	movq [r0], mm4
	movq [r0+r1], mm5
	lea r0, [r0+2*r1]
	movq [r0], mm6
	movq [r0+r1], mm7

	WELSEMMS
	LOAD_4_PARA_POP
	ret

;***********************************************************************
; void WelsCopy8x8_mmx(  uint8_t* Dst,
;                        int32_t  iStrideD,
;                        uint8_t* Src,
;                        int32_t  iStrideS )
;***********************************************************************
ALIGN 16
WelsCopy8x8_mmx:
	;push ebx
	;push esi
	;mov eax, [esp + 12]           ;Dst
	;mov ecx, [esp + 16]           ;iStrideD
	;mov esi, [esp + 20]           ;Src
	;mov ebx, [esp + 24]           ;iStrideS

	push r4
	%assign  push_num 1
    LOAD_4_PARA
	lea r4, [r3+2*r3]	;edx, [ebx+2*ebx]

	; to prefetch next loop
	prefetchnta [r2+2*r3]
	prefetchnta [r2+r4]
	movq mm0, [r2]
	movq mm1, [r2+r3]
	lea r2, [r2+2*r3]
	; to prefetch next loop
	prefetchnta [r2+2*r3]
	prefetchnta [r2+r4]
	movq mm2, [r2]
	movq mm3, [r2+r3]
	lea r2, [r2+2*r3]
	; to prefetch next loop
	prefetchnta [r2+2*r3]
	prefetchnta [r2+r4]
	movq mm4, [r2]
	movq mm5, [r2+r3]
	lea r2, [r2+2*r3]
	movq mm6, [r2]
	movq mm7, [r2+r3]

	movq [r0], mm0
	movq [r0+r1], mm1
	lea r0, [r0+2*r1]
	movq [r0], mm2
	movq [r0+r1], mm3
	lea r0, [r0+2*r1]
	movq [r0], mm4
	movq [r0+r1], mm5
	lea r0, [r0+2*r1]
	movq [r0], mm6
	movq [r0+r1], mm7

	WELSEMMS
	;pop esi
	;pop ebx
	LOAD_4_PARA_POP
	pop r4
	ret

; (dunhuang@cisco), 12/21/2011
;***********************************************************************
; void UpdateMbMv_sse2( SMVUnitXY *pMvBuffer, const SMVUnitXY sMv )
;***********************************************************************
ALIGN 16
UpdateMbMv_sse2:

    %assign  push_num 0
    LOAD_2_PARA

	;mov eax, [esp+4]	; mv_buffer
	;movd xmm0, [esp+8]	; _mv
	movd xmm0, r1d	; _mv
	pshufd xmm1, xmm0, $00
	movdqa [r0     ], xmm1
	movdqa [r0+0x10], xmm1
	movdqa [r0+0x20], xmm1
	movdqa [r0+0x30], xmm1
	ret

;*******************************************************************************
; Macros and other preprocessor constants
;*******************************************************************************

;*******************************************************************************
; Local Data (Read Only)
;*******************************************************************************

;SECTION .rodata data align=16

;*******************************************************************************
; Various memory constants (trigonometric values or rounding values)
;*******************************************************************************

ALIGN 16

;*******************************************************************************
; Code
;*******************************************************************************

SECTION .text

WELS_EXTERN PixelAvgWidthEq4_mmx
WELS_EXTERN PixelAvgWidthEq8_mmx
WELS_EXTERN PixelAvgWidthEq16_sse2

WELS_EXTERN McCopyWidthEq4_mmx
WELS_EXTERN McCopyWidthEq8_mmx
WELS_EXTERN McCopyWidthEq16_sse2


ALIGN 16
;*******************************************************************************
; void_t PixelAvgWidthEq4_mmx( uint8_t *pDst,  int iDstStride,
;                           uint8_t *pSrcA, int iSrcAStride,
;                           uint8_t *pSrcB, int iSrcBStride,
;                           int iHeight );
;*******************************************************************************
PixelAvgWidthEq4_mmx:

    %assign  push_num 0
    LOAD_7_PARA

%ifndef X86_32
	movsx	r1, r1d
	movsx	r3, r3d
	movsx	r5, r5d
	movsx	r6, r6d
%endif

ALIGN 4
.height_loop:
	movd        mm0, [r4]
    pavgb       mm0, [r2]
    movd        [r0], mm0

    dec         r6
    lea         r0, [r0+r1]
    lea         r2, [r2+r3]
    lea         r4, [r4+r5]
    jne         .height_loop

	WELSEMMS
	LOAD_7_PARA_POP
    ret


ALIGN 16
;*******************************************************************************
; void_t PixelAvgWidthEq8_mmx( uint8_t *pDst,  int iDstStride,
;                           uint8_t *pSrcA, int iSrcAStride,
;                           uint8_t *pSrcB, int iSrcBStride,
;                           int iHeight );
;*******************************************************************************
PixelAvgWidthEq8_mmx:

    ;push        esi
    ;push        edi
    ;push        ebp
    ;push        ebx

    ;mov         edi, [esp+20]       ; pDst
    ;mov         eax, [esp+24]       ; iDstStride
    ;mov         esi, [esp+28]       ; pSrcA
    ;mov         ecx, [esp+32]       ; iSrcAStride
    ;mov         ebp, [esp+36]       ; pSrcB
    ;mov         edx, [esp+40]       ; iSrcBStride
    ;mov         ebx, [esp+44]       ; iHeight

    %assign  push_num 0
    LOAD_7_PARA

%ifndef X86_32
	movsx	r1, r1d
	movsx	r3, r3d
	movsx	r5, r5d
	movsx	r6, r6d
%endif

ALIGN 4
.height_loop:
	movq        mm0, [r2]
    pavgb       mm0, [r4]
    movq        [r0], mm0
    movq        mm0, [r2+r3]
    pavgb       mm0, [r4+r5]
    movq		[r0+r1], mm0

    lea			r2,  [r2+2*r3]
    lea			r4,  [r4+2*r5]
    lea			r0,  [r0+2*r1]

    sub         r6, 2
    jnz         .height_loop

	WELSEMMS
	LOAD_7_PARA_POP
    ret



ALIGN 16
;*******************************************************************************
; void_t PixelAvgWidthEq16_sse2( uint8_t *pDst,  int iDstStride,
;                          uint8_t *pSrcA, int iSrcAStride,
;                          uint8_t *pSrcB, int iSrcBStride,
;                          int iHeight );
;*******************************************************************************
PixelAvgWidthEq16_sse2:

    %assign  push_num 0
    LOAD_7_PARA
%ifndef X86_32
	movsx	r1, r1d
	movsx	r3, r3d
	movsx	r5, r5d
	movsx	r6, r6d
%endif
ALIGN 4
.height_loop:
	movdqu      xmm0, [r2]
	movdqu	    xmm1, [r4]
	pavgb	    xmm0, xmm1
	;pavgb       xmm0, [r4]
    movdqu      [r0], xmm0

	movdqu      xmm0, [r2+r3]
	movdqu      xmm1, [r4+r5]
	pavgb	    xmm0, xmm1
    movdqu      [r0+r1], xmm0

	movdqu      xmm0, [r2+2*r3]
	movdqu       xmm1, [r4+2*r5]
	pavgb	    xmm0, xmm1
    movdqu      [r0+2*r1], xmm0

    lea         r2, [r2+2*r3]
    lea			r4, [r4+2*r5]
    lea			r0, [r0+2*r1]

	movdqu      xmm0, [r2+r3]
	movdqu      xmm1, [r4+r5]
	pavgb	    xmm0, xmm1
    movdqu      [r0+r1], xmm0

    lea         r2, [r2+2*r3]
    lea			r4, [r4+2*r5]
    lea			r0, [r0+2*r1]

    sub         r6, 4
    jne         .height_loop

	WELSEMMS
	LOAD_7_PARA_POP
    ret

ALIGN 16
;*******************************************************************************
;  void_t McCopyWidthEq4_mmx( uint8_t *pSrc, int iSrcStride,
;                          uint8_t *pDst, int iDstStride, int iHeight )
;*******************************************************************************
McCopyWidthEq4_mmx:
    ;push    esi
    ;push    edi
    ;push    ebx


    ;mov esi,  [esp+16]
    ;mov eax, [esp+20]
    ;mov edi,  [esp+24]
    ;mov ecx,  [esp+28]
    ;mov edx,  [esp+32]

    push	r5
    %assign  push_num 1
    LOAD_5_PARA

%ifndef X86_32
	movsx	r1, r1d
	movsx	r3, r3d
	movsx	r4, r4d
%endif

ALIGN 4
.height_loop:
	mov r5d, [r0]
	mov [r2], r5d

	add r0, r1
	add r2, r3
	dec r4
	jnz .height_loop
	WELSEMMS
    LOAD_5_PARA_POP
    pop	   r5
    ret

ALIGN 16
;*******************************************************************************
;   void_t McCopyWidthEq8_mmx( uint8_t *pSrc, int iSrcStride,
;                           uint8_t *pDst, int iDstStride, int iHeight )
;*******************************************************************************
McCopyWidthEq8_mmx:
    ;push  esi
    ;push  edi
	;mov  esi, [esp+12]
	;mov eax, [esp+16]
	;mov edi, [esp+20]
	;mov ecx, [esp+24]
	;mov edx, [esp+28]

    %assign  push_num 0
    LOAD_5_PARA

%ifndef X86_32
	movsx	r1, r1d
	movsx	r3, r3d
	movsx	r4, r4d
%endif

ALIGN 4
.height_loop:
	movq mm0, [r0]
	movq [r2], mm0
	add r0, r1
	add r2, r3
	dec r4
	jnz .height_loop

	WELSEMMS
	LOAD_5_PARA_POP
    ret


ALIGN 16
;*******************************************************************************
;   void_t McCopyWidthEq16_sse2( uint8_t *pSrc, int iSrcStride, uint8_t *pDst, int iDstStride, int iHeight )
;*******************************************************************************
;read unaligned memory
%macro SSE_READ_UNA 2
	movq	%1, [%2]
	movhps	%1,	[%2+8]
%endmacro

;write unaligned memory
%macro SSE_WRITE_UNA 2
	movq	[%1],	%2
	movhps	[%1+8], %2
%endmacro
McCopyWidthEq16_sse2:
    ;push    esi
    ;push    edi

    ;mov     esi, [esp+12]       ; pSrc
    ;mov     eax, [esp+16]       ; iSrcStride
    ;mov     edi, [esp+20]       ; pDst
    ;mov     edx, [esp+24]       ; iDstStride
    ;mov     ecx, [esp+28]       ; iHeight

    %assign  push_num 0
    LOAD_5_PARA
%ifndef X86_32
	movsx	r1, r1d
	movsx	r3, r3d
	movsx	r4, r4d
%endif
ALIGN 4
.height_loop:
    SSE_READ_UNA	xmm0, r0
    SSE_READ_UNA	xmm1, r0+r1
    SSE_WRITE_UNA	r2, xmm0
    SSE_WRITE_UNA	r2+r3, xmm1

	sub		r4,	2
    lea     r0, [r0+r1*2]
    lea     r2, [r2+r3*2]
    jnz     .height_loop

	LOAD_5_PARA_POP
    ret
