1e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* Copyright (c) 2010 Xiph.Org Foundation
2e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * Copyright (c) 2013 Parrot */
3e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/*
4e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   Redistribution and use in source and binary forms, with or without
5e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   modification, are permitted provided that the following conditions
6e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   are met:
7e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
8e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   - Redistributions of source code must retain the above copyright
9e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   notice, this list of conditions and the following disclaimer.
10e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
11e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   - Redistributions in binary form must reproduce the above copyright
12e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   notice, this list of conditions and the following disclaimer in the
13e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   documentation and/or other materials provided with the distribution.
14e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
15e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org*/
27e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
28e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* Original code from libtheora modified to suit to Opus */
29e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
30e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#ifdef HAVE_CONFIG_H
31e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "config.h"
32e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
33e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
34e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#ifdef OPUS_HAVE_RTCD
35e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
36e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "armcpu.h"
37e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "cpu_support.h"
38e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "os_support.h"
39e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "opus_types.h"
40e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
41e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#define OPUS_CPU_ARM_V4    (1)
42e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#define OPUS_CPU_ARM_EDSP  (1<<1)
43e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#define OPUS_CPU_ARM_MEDIA (1<<2)
44e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#define OPUS_CPU_ARM_NEON  (1<<3)
45e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
46e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#if defined(_MSC_VER)
47e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
48e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org# define WIN32_LEAN_AND_MEAN
49e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org# define WIN32_EXTRA_LEAN
50e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org# include <windows.h>
51e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
523c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){
53e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  opus_uint32 flags;
54e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  flags=0;
553c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com  /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit
56e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   * instructions via their assembled hex code.
57e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   * All of these instructions should be essentially nops. */
583c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# if defined(OPUS_ARM_MAY_HAVE_EDSP)
59e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  __try{
60e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /*PLD [r13]*/
61e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    __emit(0xF5DDF000);
62e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    flags|=OPUS_CPU_ARM_EDSP;
63e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  }
64e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
65e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /*Ignore exception.*/
66e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  }
673c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#  if defined(OPUS_ARM_MAY_HAVE_MEDIA)
68e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  __try{
69e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /*SHADD8 r3,r3,r3*/
70e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    __emit(0xE6333F93);
71e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    flags|=OPUS_CPU_ARM_MEDIA;
72e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  }
73e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
74e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /*Ignore exception.*/
75e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  }
763c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#   if defined(OPUS_ARM_MAY_HAVE_NEON)
77e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  __try{
78e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /*VORR q0,q0,q0*/
79e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    __emit(0xF2200150);
80e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    flags|=OPUS_CPU_ARM_NEON;
81e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  }
82e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
83e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /*Ignore exception.*/
84e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  }
85e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#   endif
86e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#  endif
87e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org# endif
88e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  return flags;
89e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
90e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
91e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#elif defined(__linux__)
92e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* Linux based */
93e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgopus_uint32 opus_cpu_capabilities(void)
94e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
95e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  opus_uint32 flags = 0;
96e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  FILE *cpuinfo;
97e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
98e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on
99e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   * Android */
100e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  cpuinfo = fopen("/proc/cpuinfo", "r");
101e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
102e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  if(cpuinfo != NULL)
103e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  {
104e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    /* 512 should be enough for anybody (it's even enough for all the flags that
105e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org     * x86 has accumulated... so far). */
106e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    char buf[512];
107e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
108e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    while(fgets(buf, 512, cpuinfo) != NULL)
109e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    {
1103c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_NEON)
111e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      /* Search for edsp and neon flag */
112e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if(memcmp(buf, "Features", 8) == 0)
113e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
114e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        char *p;
1153c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#  if defined(OPUS_ARM_MAY_HAVE_EDSP)
116e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        p = strstr(buf, " edsp");
117e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
118e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          flags |= OPUS_CPU_ARM_EDSP;
1193c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#  endif
120e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
1213c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#  if defined(OPUS_ARM_MAY_HAVE_NEON)
122e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        p = strstr(buf, " neon");
123e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
124e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          flags |= OPUS_CPU_ARM_NEON;
1253c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#  endif
126e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
1273c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# endif
128e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
1293c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
130e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      /* Search for media capabilities (>= ARMv6) */
131e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if(memcmp(buf, "CPU architecture:", 17) == 0)
132e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
133e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        int version;
134e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        version = atoi(buf+17);
135e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
136e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org        if(version >= 6)
137e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          flags |= OPUS_CPU_ARM_MEDIA;
138e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
1393c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# endif
140e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    }
141e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
142e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    fclose(cpuinfo);
143e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  }
144e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  return flags;
145e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
146e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#else
147e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* The feature registers which can tell us what the processor supports are
148e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * accessible in priveleged modes only, so we can't have a general user-space
149e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * detection method like on x86.*/
150e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org# error "Configured to use ARM asm but no CPU detection method available for " \
151e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   "your platform.  Reconfigure with --disable-rtcd (or send patches)."
152e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
153e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
154e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgint opus_select_arch(void)
155e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
156e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  opus_uint32 flags = opus_cpu_capabilities();
157e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int arch = 0;
158e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
159e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  if(!(flags & OPUS_CPU_ARM_EDSP))
160e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    return arch;
161e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  arch++;
162e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
163e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  if(!(flags & OPUS_CPU_ARM_MEDIA))
164e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    return arch;
165e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  arch++;
166e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
167e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  if(!(flags & OPUS_CPU_ARM_NEON))
168e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    return arch;
169e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  arch++;
170e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
171e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  return arch;
172e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
173e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
174e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
175