Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
[platform/upstream/pulseaudio.git] / src / pulsecore / svolume_arm.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk>
6
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <pulse/timeval.h>
28 #include <pulsecore/random.h>
29 #include <pulsecore/macro.h>
30 #include <pulsecore/g711.h>
31 #include <pulsecore/core-util.h>
32
33 #include "cpu-arm.h"
34
35 #include "sample-util.h"
36 #include "endianmacros.h"
37
38 #if defined (__arm__)
39
40 #define MOD_INC() \
41     " subs  r0, r6, %2              \n\t" \
42     " addcs r0, %1                  \n\t" \
43     " movcs r6, r0                  \n\t"
44
45 static void
46 pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
47 {
48     int32_t *ve;
49
50     channels = PA_MAX (4U, channels);
51     ve = volumes + channels;
52
53     __asm__ __volatile__ (
54         " mov r6, %1                      \n\t"
55         " mov %3, %3, LSR #1              \n\t" /* length /= sizeof (int16_t) */
56         " tst %3, #1                      \n\t" /* check for odd samples */
57         " beq  2f                         \n\t"
58
59         "1:                               \n\t"
60         " ldr  r0, [r6], #4               \n\t" /* odd samples volumes */
61         " ldrh r2, [%0]                   \n\t"
62
63         " smulwb r0, r0, r2               \n\t"
64         " ssat r0, #16, r0                \n\t"
65
66         " strh r0, [%0], #2               \n\t"
67
68         MOD_INC()
69
70         "2:                               \n\t"
71         " mov %3, %3, LSR #1              \n\t"
72         " tst %3, #1                      \n\t" /* check for odd samples */
73         " beq  4f                         \n\t"
74
75         "3:                               \n\t"
76         " ldrd r2, [r6], #8               \n\t" /* 2 samples at a time */
77         " ldr  r0, [%0]                   \n\t"
78
79         " smulwt r2, r2, r0               \n\t"
80         " smulwb r3, r3, r0               \n\t"
81
82         " ssat r2, #16, r2                \n\t"
83         " ssat r3, #16, r3                \n\t"
84
85         " pkhbt r0, r3, r2, LSL #16       \n\t"
86         " str  r0, [%0], #4               \n\t"
87
88         MOD_INC()
89
90         "4:                               \n\t"
91         " movs %3, %3, LSR #1             \n\t"
92         " beq  6f                         \n\t"
93
94         "5:                               \n\t"
95         " ldrd r2, [r6], #8               \n\t" /* 4 samples at a time */
96         " ldrd r4, [r6], #8               \n\t"
97         " ldrd r0, [%0]                   \n\t"
98
99         " smulwt r2, r2, r0               \n\t"
100         " smulwb r3, r3, r0               \n\t"
101         " smulwt r4, r4, r1               \n\t"
102         " smulwb r5, r5, r1               \n\t"
103
104         " ssat r2, #16, r2                \n\t"
105         " ssat r3, #16, r3                \n\t"
106         " ssat r4, #16, r4                \n\t"
107         " ssat r5, #16, r5                \n\t"
108
109         " pkhbt r0, r3, r2, LSL #16       \n\t"
110         " pkhbt r1, r5, r4, LSL #16       \n\t"
111         " strd  r0, [%0], #8              \n\t"
112
113         MOD_INC()
114
115         " subs %3, %3, #1                 \n\t"
116         " bne 5b                          \n\t"
117         "6:                               \n\t"
118
119         : "+r" (samples), "+r" (volumes), "+r" (ve), "+r" (length)
120         :
121         : "r6", "r5", "r4", "r3", "r2", "r1", "r0", "cc"
122     );
123 }
124
125 #undef RUN_TEST
126
127 #ifdef RUN_TEST
128 #define CHANNELS 2
129 #define SAMPLES 1023
130 #define TIMES 1000
131 #define PADDING 16
132
133 static void run_test (void) {
134     int16_t samples[SAMPLES];
135     int16_t samples_ref[SAMPLES];
136     int16_t samples_orig[SAMPLES];
137     int32_t volumes[CHANNELS + PADDING];
138     int i, j, padding;
139     pa_do_volume_func_t func;
140     pa_usec_t start, stop;
141
142     func = pa_get_volume_func (PA_SAMPLE_S16NE);
143
144     printf ("checking ARM %zd\n", sizeof (samples));
145
146     pa_random (samples, sizeof (samples));
147     memcpy (samples_ref, samples, sizeof (samples));
148     memcpy (samples_orig, samples, sizeof (samples));
149
150     for (i = 0; i < CHANNELS; i++)
151         volumes[i] = rand() >> 1;
152     for (padding = 0; padding < PADDING; padding++, i++)
153         volumes[i] = volumes[padding];
154
155     func (samples_ref, volumes, CHANNELS, sizeof (samples));
156     pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples));
157     for (i = 0; i < SAMPLES; i++) {
158         if (samples[i] != samples_ref[i]) {
159             printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i],
160                   samples_orig[i], volumes[i % CHANNELS]);
161         }
162     }
163
164     start = pa_rtclock_now();
165     for (j = 0; j < TIMES; j++) {
166         memcpy (samples, samples_orig, sizeof (samples));
167         pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples));
168     }
169     stop = pa_rtclock_now();
170     pa_log_info("ARM: %llu usec.", (long long unsigned int) (stop - start));
171
172     start = pa_rtclock_now();
173     for (j = 0; j < TIMES; j++) {
174         memcpy (samples_ref, samples_orig, sizeof (samples));
175         func (samples_ref, volumes, CHANNELS, sizeof (samples));
176     }
177     stop = pa_rtclock_now();
178     pa_log_info("ref: %llu usec.", (long long unsigned int) (stop - start));
179 }
180 #endif
181
182 #endif /* defined (__arm__) */
183
184
185 void pa_volume_func_init_arm (pa_cpu_arm_flag_t flags) {
186 #if defined (__arm__)
187     pa_log_info("Initialising ARM optimized functions.");
188
189 #ifdef RUN_TEST
190     run_test ();
191 #endif
192
193     pa_set_volume_func (PA_SAMPLE_S16NE,     (pa_do_volume_func_t) pa_volume_s16ne_arm);
194 #endif /* defined (__arm__) */
195 }