;
; idcts.s
; Copyright (C) 2002 P.Everett <peter@everett9981.freeserve.co.uk>
;
; This file is part of KinoAMP, a free RISCOS MPEG program stream decoder.
;
; KinoAMP 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; either version 2 of the License, or
; (at your option) any later version.
;
; KinoAMP 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 this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
;

; Thanks to Andr Timmermans for this code.


  AREA |A$$code|, CODE, READONLY
;  AREA    |mpeg$$idctscode|, CODE, READONLY

  EXPORT  idct_block_copy_neon
  EXPORT  idct_block_add_neon
  EXPORT  idct_block_copy_dc_neon
  EXPORT  idct_block_add_dc_neon
  ; for tests
  EXPORT  idct_rows_neon
  EXPORT  idct_cols_neon
  EXPORT  idct_clip_copy_neon
  EXPORT  idct_clip_add_neon

ROWS_SHIFT *  8
COLS_SHIFT * 17
W_SHIFT    * 11

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
;-------------------------------------------------------------------------------
 ALIGN 32
idct_block_copy_dc_neon
  stmfd r13!,{r3, r14}
  ; DC = (block[0] + 4) >> 3
  ldr   r0, [r0,#0]
  add   r0, r0, #4
  movs  r0, r0, asr #3
  movmi r0, #0
  cmp   r0, #255
  movgt r0, #255
  orr   r0, r0, r0, lsl #8
  orr   r0, r0, r0, lsl #16
  mov   r3, r0

  stmia r1, {r0, r3}
  add   r1, r1, r2
  stmia r1, {r0, r3}
  add   r1, r1, r2
  stmia r1, {r0, r3}
  add   r1, r1, r2
  stmia r1, {r0, r3}
  add   r1, r1, r2
  stmia r1, {r0, r3}
  add   r1, r1, r2
  stmia r1, {r0, r3}
  add   r1, r1, r2
  stmia r1, {r0, r3}
  add   r1, r1, r2
  stmia r1, {r0, r3}
  add   r1, r1, r2

  ldmfd r13!,{r3, pc}


;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
;-------------------------------------------------------------------------------
 ALIGN 32
idct_block_add_dc_neon
  stmfd r13!,{r3, r14}
  ; DC = (block[0] + 4) >> 3
  vld1.32 {d0[], d1[]}, [r0]
  vqrshrn.s32 d0, q0, #3
  vmov  d1, d0

  vld1.8    { d2}, [r1], r2
  vld1.8    { d4}, [r1], r2
  vld1.8    { d6}, [r1], r2
  vld1.8    { d8}, [r1], r2
  vld1.8    {d10}, [r1], r2
  vld1.8    {d12}, [r1], r2
  vld1.8    {d14}, [r1], r2
  vld1.8    {d16}, [r1], r2
  sub       r1,r1, r2, lsl #3
  vmovl.u8  q1,  d2
  vmovl.u8  q2,  d4
  vmovl.u8  q3,  d6
  vmovl.u8  q4,  d8
  vmovl.u8  q5, d10
  vmovl.u8  q6, d12
  vmovl.u8  q7, d14
  vmovl.u8  q8, d16
  vqadd.s16 q1, q1, q0
  vqadd.s16 q2, q2, q0
  vqadd.s16 q3, q3, q0
  vqadd.s16 q4, q4, q0
  vqadd.s16 q5, q5, q0
  vqadd.s16 q6, q6, q0
  vqadd.s16 q7, q7, q0
  vqadd.s16 q8, q8, q0
  vqmovun.s16  d2, q1
  vqmovun.s16  d4, q2
  vqmovun.s16  d6, q3
  vqmovun.s16  d8, q4
  vqmovun.s16 d10, q5
  vqmovun.s16 d12, q6
  vqmovun.s16 d14, q7
  vqmovun.s16 d16, q8
  vst1.8    { d2}, [r1], r2
  vst1.8    { d4}, [r1], r2
  vst1.8    { d6}, [r1], r2
  vst1.8    { d8}, [r1], r2
  vst1.8    {d10}, [r1], r2
  vst1.8    {d12}, [r1], r2
  vst1.8    {d14}, [r1], r2
  vst1.8    {d16}, [r1], r2

  ldmfd r13!,{r3, pc}

;-------------------------------------------------------------------------------
;  BUTTERFLY(ta,tb,Wa,Wb,da,db)
;  {
;    ta = Wa * da + Wb * db;
;    tb = Wa * db - Wb * dq;
;  }
;  q2 = (x0 + x4) << 11;
;  q6 = (x0 - x4) << 11;
;  BUTTERFLY(q15, q14, W6, W2, x6, x2);

;  q11 = q2 - q15;
;  q2  = q2 + q15;
;  q10 = q6 + q14;
;  q4  = q6 - q14;

;  BUTTERFLY(q15, q14, W7, W1, x7, x1);
;  BUTTERFLY(q13, q12, W3, W5, x3, x5);

;  q7  = q15 - q13;
;  q6  = q14 - q12;
;  q13 = q15 + q13;
;  q12 = q14 + q12;
;  q15 = (181 * (q7 + q6) + 128) >> 8;
;  q14 = (181 * (q7 - q6) + 128) >> 8;

;  x7 = q2  - q13;
;  x0 = q2  + q13;
;  x6 = q10 - q15;
;  x1 = q10 + q15;
;  x5 = q4  - q14;
;  x2 = q4  + q14;
;  x4 = q11 - q12;
;  x3 = q11 + q12;

; q0+q1[i]   Wi
; qi+2       Xi [0-3]
;-------------------------------------------------------------------------------
idct_butterfly_x4
  vshl.s32 q15,  q2, #W_SHIFT
  vshl.s32 q14,  q6, #W_SHIFT
  vadd.s32 q2 , q15, q14
  vsub.s32 q6 , q15, q14
  vmul.s32 q15,  q8, d3[0] ; W6
  vmul.s32 q14,  q4, d3[0] ; W6
  vmla.s32 q15,  q4, d1[0] ; W2
  vmls.s32 q14,  q8, d1[0] ; W2

  vsub.s32 q11,  q2, q15
  vadd.s32 q2 ,  q2, q15
  vadd.s32 q10,  q6, q14
  vsub.s32 q4 ,  q6, q14

  vmul.s32 q15,  q9, d3[1] ; W7
  vmul.s32 q14,  q3, d3[1] ; W7
  vmla.s32 q15,  q3, d0[1] ; W1
  vmls.s32 q14,  q9, d0[1] ; W1
  vmul.s32 q13,  q5, d1[1] ; W3
  vmul.s32 q12,  q7, d1[1] ; W3
  vmla.s32 q13,  q7, d2[1] ; W5
  vmls.s32 q12,  q5, d2[1] ; W5

  vsub.s32 q7 , q15, q13
  vsub.s32 q6 , q14, q12
  vadd.s32 q13, q15, q13
  vadd.s32 q12, q14, q12

  vadd.s32 q15, q7 , q6
  vsub.s32 q14, q7 , q6
  vmul.s32 q15, q15, d0[0] ; 181
  vmul.s32 q14, q14, d0[0] ; 181
  vrshr.s32 q15, q15, #8
  vrshr.s32 q14, q14, #8

  vsub.s32 q9, q2 , q13
  vadd.s32 q2, q2 , q13
  vsub.s32 q8, q10, q15
  vadd.s32 q3, q10, q15
  vsub.s32 q7, q4 , q14
  vadd.s32 q4, q4 , q14
  vsub.s32 q6, q11, q12
  vadd.s32 q5, q11, q12

  mov pc, r14

idct_butterfly_x4_shift
  vshl.s32 q15,  q2, #W_SHIFT
  vshl.s32 q14,  q6, #W_SHIFT
  vadd.s32 q2 , q15, q14
  vsub.s32 q6 , q15, q14
  vmul.s32 q15,  q8, d3[0] ; W6
  vmul.s32 q14,  q4, d3[0] ; W6
  vmla.s32 q15,  q4, d1[0] ; W2
  vmls.s32 q14,  q8, d1[0] ; W2

  vsub.s32 q11,  q2, q15
  vadd.s32 q2 ,  q2, q15
  vadd.s32 q10,  q6, q14
  vsub.s32 q4 ,  q6, q14
  vrshr.s32 q11, q11, #3
  vrshr.s32 q2 ,  q2, #3
  vrshr.s32 q10, q10, #3
  vrshr.s32 q4 ,  q4, #3

  vmul.s32 q15,  q9, d3[1] ; W7
  vmul.s32 q14,  q3, d3[1] ; W7
  vmla.s32 q15,  q3, d0[1] ; W1
  vmls.s32 q14,  q9, d0[1] ; W1
  vmul.s32 q13,  q5, d1[1] ; W3
  vmul.s32 q12,  q7, d1[1] ; W3
  vmla.s32 q13,  q7, d2[1] ; W5
  vmls.s32 q12,  q5, d2[1] ; W5

  vsub.s32 q7 , q15, q13
  vsub.s32 q6 , q14, q12
  vadd.s32 q13, q15, q13
  vadd.s32 q12, q14, q12
  vshr.s32 q7 ,  q7, #3
  vshr.s32 q6 ,  q6, #3
  vshr.s32 q13, q13, #3
  vshr.s32 q12, q12, #3

  vadd.s32 q15, q7 , q6
  vsub.s32 q14, q7 , q6
  vmul.s32 q15, q15, d0[0] ; 181
  vmul.s32 q14, q14, d0[0] ; 181
  vrshr.s32 q15, q15, #8
  vrshr.s32 q14, q14, #8

  vsub.s32 q9, q2 , q13
  vadd.s32 q2, q2 , q13
  vsub.s32 q8, q10, q15
  vadd.s32 q3, q10, q15
  vsub.s32 q7, q4 , q14
  vadd.s32 q4, q4 , q14
  vsub.s32 q6, q11, q12
  vadd.s32 q5, q11, q12

  mov pc, r14

;-------------------------------------------------------------------------------
; q0+q1[i]    Wi
; r0  block   64x32-bit
; Out:
; r0 updated for next call
;-------------------------------------------------------------------------------
idct_cols4
  stmdb r13!, {r3, r14}

  mov r3, #8*4
 ; 4 columns of 8 words
  vld1.32 {q2}, [r0], r3 ; q2 = x0[0-3]
  vld1.32 {q3}, [r0], r3 ; q3 = x1[0-3]
  vld1.32 {q4}, [r0], r3 ; q4 = x2[0-3]
  vld1.32 {q5}, [r0], r3 ; q5 = x3[0-3]
  vld1.32 {q6}, [r0], r3 ; q6 = x4[0-3]
  vld1.32 {q7}, [r0], r3 ; q7 = x5[0-3]
  vld1.32 {q8}, [r0], r3 ; q8 = x6[0-3]
  vld1.32 {q9}, [r0], r3 ; q9 = x7[0-3]

  bl idct_butterfly_x4_shift
  vrshr.s32 q2, q2, #COLS_SHIFT-3
  vrshr.s32 q3, q3, #COLS_SHIFT-3
  vrshr.s32 q4, q4, #COLS_SHIFT-3
  vrshr.s32 q5, q5, #COLS_SHIFT-3
  vrshr.s32 q6, q6, #COLS_SHIFT-3
  vrshr.s32 q7, q7, #COLS_SHIFT-3
  vrshr.s32 q8, q8, #COLS_SHIFT-3
  vrshr.s32 q9, q9, #COLS_SHIFT-3

  sub r0, r0, r3, lsl #3
  vst1.32 {q2}, [r0], r3
  vst1.32 {q3}, [r0], r3
  vst1.32 {q4}, [r0], r3
  vst1.32 {q5}, [r0], r3
  vst1.32 {q6}, [r0], r3
  vst1.32 {q7}, [r0], r3
  vst1.32 {q8}, [r0], r3
  vst1.32 {q9}, [r0], r3

  sub r0, r0, r3, lsl #3
  add r0, r0, #4*4

  ldmia r13!, {r3, pc}

;-------------------------------------------------------------------------------
; q0+q1[i]    Wi
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
; Out:
; r0, r1 updated for next call
;-------------------------------------------------------------------------------
idct_cols4_copy
  stmdb r13!, {r2-r3, r14}

  mov r3, #8*4
  ; 4 columns of 8 words
  vld1.32 {q2}, [r0], r3 ; q2 = x0[0-3]
  vld1.32 {q3}, [r0], r3 ; q3 = x1[0-3]
  vld1.32 {q4}, [r0], r3 ; q4 = x2[0-3]
  vld1.32 {q5}, [r0], r3 ; q5 = x3[0-3]
  vld1.32 {q6}, [r0], r3 ; q6 = x4[0-3]
  vld1.32 {q7}, [r0], r3 ; q7 = x5[0-3]
  vld1.32 {q8}, [r0], r3 ; q8 = x6[0-3]
  vld1.32 {q9}, [r0], r3 ; q9 = x7[0-3]

  bl idct_butterfly_x4_shift
  ; shift and saturate into [0-255]
  ; from s32 to s16
  vqrshrn.s32 d20, q2, #COLS_SHIFT-3 ; x0[0-3]
  vqrshrn.s32 d21, q3, #COLS_SHIFT-3 ; x1[0-3]
  vqrshrn.s32 d22, q4, #COLS_SHIFT-3 ; x2[0-3]
  vqrshrn.s32 d23, q5, #COLS_SHIFT-3 ; x3[0-3]
  vqrshrn.s32 d24, q6, #COLS_SHIFT-3 ; x4[0-3]
  vqrshrn.s32 d25, q7, #COLS_SHIFT-3 ; x5[0-3]
  vqrshrn.s32 d26, q8, #COLS_SHIFT-3 ; x6[0-3]
  vqrshrn.s32 d27, q9, #COLS_SHIFT-3 ; x7[0-3]
  ; from s16 to u8
  vqmovun.s16 d28, q10 ; x0[0-3], x1[0-3]
  vqmovun.s16 d29, q11 ; x2[0-3], x3[0-3]
  vqmovun.s16 d30, q12 ; x4[0-3], x5[0-3]
  vqmovun.s16 d31, q13 ; x6[0-3], x7[0-3]

  vst1.32 {d28[0]}, [r1], r2
  vst1.32 {d28[1]}, [r1], r2
  vst1.32 {d29[0]}, [r1], r2
  vst1.32 {d29[1]}, [r1], r2
  vst1.32 {d30[0]}, [r1], r2
  vst1.32 {d30[1]}, [r1], r2
  vst1.32 {d31[0]}, [r1], r2
  vst1.32 {d31[1]}, [r1], r2

  sub r0, r0, r3, lsl #3
  add r0, r0, #4*4
  sub r1, r1, r2, lsl #3
  add r1, r1, #4

  ldmia r13!, {r2-r3, pc}

;-------------------------------------------------------------------------------
; q0+q1[i]    Wi
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
; Out:
; r0, r1 updated for next call
;-------------------------------------------------------------------------------
idct_cols4_add
  stmdb r13!, {r2-r3, r14}

  mov r3, #8*4
  ; 4 columns of 8 words
  vld1.32 {q2}, [r0], r3 ; q2 = x0[0-3]
  vld1.32 {q3}, [r0], r3 ; q3 = x1[0-3]
  vld1.32 {q4}, [r0], r3 ; q4 = x2[0-3]
  vld1.32 {q5}, [r0], r3 ; q5 = x3[0-3]
  vld1.32 {q6}, [r0], r3 ; q6 = x4[0-3]
  vld1.32 {q7}, [r0], r3 ; q7 = x5[0-3]
  vld1.32 {q8}, [r0], r3 ; q8 = x6[0-3]
  vld1.32 {q9}, [r0], r3 ; q9 = x7[0-3]

  bl idct_butterfly_x4_shift
  ; shift and saturate into [0-255]
  ; from s32 to s16
  vqrshrn.s32 d20, q2, #COLS_SHIFT-3 ; x0[0-3]
  vqrshrn.s32 d21, q3, #COLS_SHIFT-3 ; x1[0-3]
  vqrshrn.s32 d22, q4, #COLS_SHIFT-3 ; x2[0-3]
  vqrshrn.s32 d23, q5, #COLS_SHIFT-3 ; x3[0-3]
  vqrshrn.s32 d24, q6, #COLS_SHIFT-3 ; x4[0-3]
  vqrshrn.s32 d25, q7, #COLS_SHIFT-3 ; x5[0-3]
  vqrshrn.s32 d26, q8, #COLS_SHIFT-3 ; x6[0-3]
  vqrshrn.s32 d27, q9, #COLS_SHIFT-3 ; x7[0-3]
  ; add
  vld1.32 {d16[0]}, [r1], r2
  vld1.32 {d16[1]}, [r1], r2
  vld1.32 {d17[0]}, [r1], r2
  vld1.32 {d17[1]}, [r1], r2
  vld1.32 {d18[0]}, [r1], r2
  vld1.32 {d18[1]}, [r1], r2
  vld1.32 {d19[0]}, [r1], r2
  vld1.32 {d19[1]}, [r1], r2
  sub r1, r1, r2, lsl #3
  vmovl.u8 q2, d16
  vmovl.u8 q3, d17
  vmovl.u8 q4, d18
  vmovl.u8 q5, d19
  vqadd.s16 q10, q10, q2
  vqadd.s16 q11, q11, q3
  vqadd.s16 q12, q12, q4
  vqadd.s16 q13, q13, q5
  ; from s16 to u8
  vqmovun.s16 d28, q10 ; x0[0-3], x1[0-3]
  vqmovun.s16 d29, q11 ; x2[0-3], x3[0-3]
  vqmovun.s16 d30, q12 ; x4[0-3], x5[0-3]
  vqmovun.s16 d31, q13 ; x6[0-3], x7[0-3]

  vst1.32 {d28[0]}, [r1], r2
  vst1.32 {d28[1]}, [r1], r2
  vst1.32 {d29[0]}, [r1], r2
  vst1.32 {d29[1]}, [r1], r2
  vst1.32 {d30[0]}, [r1], r2
  vst1.32 {d30[1]}, [r1], r2
  vst1.32 {d31[0]}, [r1], r2
  vst1.32 {d31[1]}, [r1], r2

  sub r0, r0, r3, lsl #3
  add r0, r0, #4*4
  sub r1, r1, r2, lsl #3
  add r1, r1, #4

  ldmia r13!, {r2-r3, pc}

;-------------------------------------------------------------------------------
; q0+q1[i]    Wi
; r0  block   64x32-bit
; Out:
; r0 updated for next call
;-------------------------------------------------------------------------------
idct_rows4
  stmdb r13!, {r4, r14}

  ; 4 rows of 8 words
  vld4.32 {d4[0], d6[0], d8[0], d10[0]}, [r0]!    ;x0[0], x1[0], x2[0], x3[0]
  vld4.32 {d12[0], d14[0], d16[0], d18[0]}, [r0]! ;x4[0], x5[0], x6[0], x7[0]
  vld4.32 {d4[1], d6[1], d8[1], d10[1]}, [r0]!    ;x0[1], x1[1], x2[1], x3[1]
  vld4.32 {d12[1], d14[1], d16[1], d18[1]}, [r0]! ;x4[1], x5[1], x6[1], x7[1]
  vld4.32 {d5[0], d7[0], d9[0], d11[0]}, [r0]!    ;x0[2], x1[2], x2[2], x3[2]
  vld4.32 {d13[0], d15[0], d17[0], d19[0]}, [r0]! ;x4[2], x5[2], x6[2], x7[2]
  vld4.32 {d5[1], d7[1], d9[1], d11[1]}, [r0]!    ;x0[3], x1[3], x2[3], x3[3]
  vld4.32 {d13[1], d15[1], d17[1], d19[1]}, [r0]! ;x4[3], x5[3], x6[3], x7[3]

  bl idct_butterfly_x4
  vrshr.s32 q2, q2, #ROWS_SHIFT
  vrshr.s32 q3, q3, #ROWS_SHIFT
  vrshr.s32 q4, q4, #ROWS_SHIFT
  vrshr.s32 q5, q5, #ROWS_SHIFT
  vrshr.s32 q6, q6, #ROWS_SHIFT
  vrshr.s32 q7, q7, #ROWS_SHIFT
  vrshr.s32 q8, q8, #ROWS_SHIFT
  vrshr.s32 q9, q9, #ROWS_SHIFT

  sub r0, r0, #32*4
  vst4.32 {d4[0], d6[0], d8[0], d10[0]}, [r0]!
  vst4.32 {d12[0], d14[0], d16[0], d18[0]}, [r0]!
  vst4.32 {d4[1], d6[1], d8[1], d10[1]}, [r0]!
  vst4.32 {d12[1], d14[1], d16[1], d18[1]}, [r0]!
  vst4.32 {d5[0], d7[0], d9[0], d11[0]}, [r0]!
  vst4.32 {d13[0], d15[0], d17[0], d19[0]}, [r0]!
  vst4.32 {d5[1], d7[1], d9[1], d11[1]}, [r0]!
  vst4.32 {d13[1], d15[1], d17[1], d19[1]}, [r0]!

  ldmia r13!, {r4, pc}

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
; out:
; r0, r1 updated for next call
;-------------------------------------------------------------------------------
dest_copy4_clipped
  stmdb r13!, {r4, r14}

  ; saturate into [0-255]
  vld1.32 {q0-q1}, [r0]!
  vld1.32 {q2-q3}, [r0]!
  vld1.32 {q4-q5}, [r0]!
  vld1.32 {q6-q7}, [r0]!
  ; from s32 to s16
  vqmovn.s32 d20, q0
  vqmovn.s32 d21, q1
  vqmovn.s32 d22, q2
  vqmovn.s32 d23, q3
  vqmovn.s32 d24, q4
  vqmovn.s32 d25, q5
  vqmovn.s32 d26, q6
  vqmovn.s32 d27, q7
  ; from s16 to u8
  vqmovun.s16 d28, q10
  vqmovun.s16 d29, q11
  vqmovun.s16 d30, q12
  vqmovun.s16 d31, q13
  vst1.8 {d28}, [r1], r2
  vst1.8 {d29}, [r1], r2
  vst1.8 {d30}, [r1], r2
  vst1.8 {d31}, [r1], r2

  ldmia r13!, {r4, pc}

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
; out:
; r0, r1 updated for next call
;-------------------------------------------------------------------------------
dest_add4_clipped
  stmdb r13!, {r4, r14}

  ; saturate into [0-255]
  vld1.32 {q0-q1}, [r0]!
  vld1.32 {q2-q3}, [r0]!
  vld1.32 {q4-q5}, [r0]!
  vld1.32 {q6-q7}, [r0]!
  ; from s32 to s16
  vqmovn.s32 d20, q0
  vqmovn.s32 d21, q1
  vqmovn.s32 d22, q2
  vqmovn.s32 d23, q3
  vqmovn.s32 d24, q4
  vqmovn.s32 d25, q5
  vqmovn.s32 d26, q6
  vqmovn.s32 d27, q7
  ; add
  vld1.8 {d16}, [r1], r2
  vld1.8 {d17}, [r1], r2
  vld1.8 {d18}, [r1], r2
  vld1.8 {d19}, [r1], r2
  sub r1, r1, r2, lsl #2
  vmovl.u8 q0, d16
  vmovl.u8 q1, d17
  vmovl.u8 q2, d18
  vmovl.u8 q3, d19
  vqadd.s16 q10, q0
  vqadd.s16 q11, q1
  vqadd.s16 q12, q2
  vqadd.s16 q13, q3
  ; from s16 to u8
  vqmovun.s16 d28, q10
  vqmovun.s16 d29, q11
  vqmovun.s16 d30, q12
  vqmovun.s16 d31, q13
  vst1.8 {d28}, [r1], r2
  vst1.8 {d29}, [r1], r2
  vst1.8 {d30}, [r1], r2
  vst1.8 {d31}, [r1], r2

  ldmia r13!, {r4, pc}

  ALIGN 32
wtable ; W0 = 181, Wx= 2048*sqrt(2)*cos(x*PI/16)
  DCD  181, 2841, 2676, 2408, 2048, 1609, 1108, 565

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
;-------------------------------------------------------------------------------
idct_cols_neon
  stmdb r13!, {r0-r3, r14}

  adr r3, wtable
  vld1.32 {d0-d3}, [r3]

  bl idct_cols4
  bl idct_cols4

  ldmia r13!, {r0-r3, pc}

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
;-------------------------------------------------------------------------------
idct_rows_neon
  stmdb r13!, {r0-r3, r14}

  adr r3, wtable
  vld1.32 {d0-d3}, [r3]

  bl idct_rows4
  bl idct_rows4

  ldmia r13!, {r0-r3, pc}

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
;-------------------------------------------------------------------------------
idct_block_copy_neon
  stmdb r13!, {r4, r14}
  mov r4, r0

  adr r3, wtable
  vld1.32 {d0-d3}, [r3]

  bl idct_rows4
  bl idct_rows4

  mov r0, r4
  bl idct_cols4_copy
  bl idct_cols4_copy

;  mov r0, r4
;  bl dest_copy4_clipped
;  bl dest_copy4_clipped

  ldmia r13!, {r4, pc}

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
;-------------------------------------------------------------------------------
idct_clip_copy_neon
  stmdb r13!, {r4, r14}
  bl dest_copy4_clipped
  bl dest_copy4_clipped
  ldmia r13!, {r4, pc}

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
;-------------------------------------------------------------------------------
idct_block_add_neon
  stmdb r13!, {r4, r14}
  mov r4, r0

  adr r3, wtable
  vld1.32 {d0-d3}, [r3]

  bl idct_rows4
  bl idct_rows4

  mov r0, r4
  bl idct_cols4_add
  bl idct_cols4_add

  mov r0, r4
;  bl dest_add4_clipped
;  bl dest_add4_clipped

  ldmia r13!, {r4, pc}

;-------------------------------------------------------------------------------
; r0  block   64x32-bit
; r1  dest    8x 8x8-bit lines
; r2  stride  bytes between start of 2 consecutive lines
;-------------------------------------------------------------------------------
idct_clip_add_neon
  stmdb r13!, {r4, r14}
  bl dest_add4_clipped
  bl dest_add4_clipped
  ldmia r13!, {r4, pc}

 ALIGN 32 ; to ensure next file starts on correct boundary

  END
