cdrom: fix a copy-paste mistake
[pcsx_rearmed.git] / deps / libretro-common / features / features_cpu.c
1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (features_cpu.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #if defined(_WIN32)
27 #include <direct.h>
28 #else
29 #include <unistd.h>
30 #endif
31
32 #include <compat/strl.h>
33 #include <streams/file_stream.h>
34 #include <libretro.h>
35 #include <features/features_cpu.h>
36 #include <retro_timers.h>
37
38 #if defined(_WIN32) && !defined(_XBOX)
39 #include <windows.h>
40 #endif
41
42 #ifdef __PSL1GHT__
43 #include <lv2/systime.h>
44 #endif
45
46 #if defined(_XBOX360)
47 #include <PPCIntrinsics.h>
48 #elif !defined(__MACH__) && (defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC64__) || defined(__powerpc64__))
49 #ifndef _PPU_INTRINSICS_H
50 #include <ppu_intrinsics.h>
51 #endif
52 #elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
53 /* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
54 #include <time.h>
55 #endif
56
57 #if defined(__QNX__) && !defined(CLOCK_MONOTONIC)
58 #define CLOCK_MONOTONIC 2
59 #endif
60
61 #if defined(PSP)
62 #include <pspkernel.h>
63 #endif
64
65 #if defined(PSP) || defined(__PSL1GHT__)
66 #include <sys/time.h>
67 #endif
68
69 #if defined(PSP)
70 #include <psprtc.h>
71 #endif
72
73 #if defined(VITA)
74 #include <psp2/kernel/processmgr.h>
75 #include <psp2/rtc.h>
76 #endif
77
78 #if defined(ORBIS)
79 #include <orbis/libkernel.h>
80 #endif
81
82 #if defined(PS2)
83 #include <ps2sdkapi.h>
84 #endif
85
86 #if !defined(__PSL1GHT__) && defined(__PS3__)
87 #include <sys/sys_time.h>
88 #endif
89
90 #ifdef GEKKO
91 #include <ogc/lwp_watchdog.h>
92 #endif
93
94 #ifdef WIIU
95 #include <wiiu/os/time.h>
96 #endif
97
98 #if defined(HAVE_LIBNX)
99 #include <switch.h>
100 #elif defined(SWITCH)
101 #include <libtransistor/types.h>
102 #include <libtransistor/svc.h>
103 #endif
104
105 #if defined(_3DS)
106 #include <3ds/svc.h>
107 #include <3ds/os.h>
108 #include <3ds/services/cfgu.h>
109 #endif
110
111 /* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
112 #ifdef __MACH__
113 #include <sys/time.h>
114
115 #ifndef CLOCK_MONOTONIC
116 #define CLOCK_MONOTONIC 0
117 #endif
118
119 #ifndef CLOCK_REALTIME
120 #define CLOCK_REALTIME 0
121 #endif
122
123 /**
124  * TODO/FIXME: clock_gettime function is part of iOS 10 now
125  **/
126 static int ra_clock_gettime(int clk_ik, struct timespec *t)
127 {
128    struct timeval now;
129    int rv     = gettimeofday(&now, NULL);
130    if (rv)
131       return rv;
132    t->tv_sec  = now.tv_sec;
133    t->tv_nsec = now.tv_usec * 1000;
134    return 0;
135 }
136 #endif
137
138 #if defined(__MACH__) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
139 #else
140 #define ra_clock_gettime clock_gettime
141 #endif
142
143 #ifdef EMSCRIPTEN
144 #include <emscripten.h>
145 #endif
146
147 #if defined(BSD) || defined(__APPLE__)
148 #include <sys/sysctl.h>
149 #endif
150
151 #include <string.h>
152
153 /**
154  * cpu_features_get_perf_counter:
155  *
156  * Gets performance counter.
157  *
158  * @return Performance counter.
159  **/
160 retro_perf_tick_t cpu_features_get_perf_counter(void)
161 {
162    retro_perf_tick_t time_ticks = 0;
163 #if defined(_WIN32)
164    long tv_sec, tv_usec;
165 #if defined(_MSC_VER) && _MSC_VER <= 1200
166    static const unsigned __int64 epoch = 11644473600000000;
167 #else
168    static const unsigned __int64 epoch = 11644473600000000ULL;
169 #endif
170    FILETIME file_time;
171    SYSTEMTIME system_time;
172    ULARGE_INTEGER ularge;
173
174    GetSystemTime(&system_time);
175    SystemTimeToFileTime(&system_time, &file_time);
176    ularge.LowPart  = file_time.dwLowDateTime;
177    ularge.HighPart = file_time.dwHighDateTime;
178
179    tv_sec     = (long)((ularge.QuadPart - epoch) / 10000000L);
180    tv_usec    = (long)(system_time.wMilliseconds * 1000);
181    time_ticks = (1000000 * tv_sec + tv_usec);
182 #elif defined(GEKKO)
183    time_ticks = gettime();
184 #elif !defined(__MACH__) && (defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__) || defined(__PPC64__) || defined(__powerpc64__))
185    time_ticks = __mftb();
186 #elif (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0) || defined(__QNX__) || defined(ANDROID)
187    struct timespec tv;
188    if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
189       time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
190          (retro_perf_tick_t)tv.tv_nsec;
191
192 #elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)
193    __asm__ volatile ("rdtsc" : "=A" (time_ticks));
194 #elif defined(__GNUC__) && defined(__x86_64__) || defined(_M_IX86)
195    unsigned a, d;
196    __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
197    time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
198 #elif defined(__ARM_ARCH_6__)
199    __asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
200 #elif defined(__aarch64__)
201    __asm__ volatile( "mrs %0, cntvct_el0" : "=r"(time_ticks) );
202 #elif defined(PSP) || defined(VITA)
203    time_ticks = sceKernelGetSystemTimeWide();
204 #elif defined(ORBIS)
205    sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);
206 #elif defined(PS2)
207    time_ticks = ps2_clock();
208 #elif defined(_3DS)
209    time_ticks = svcGetSystemTick();
210 #elif defined(WIIU)
211    time_ticks = OSGetSystemTime();
212 #elif defined(HAVE_LIBNX)
213    time_ticks = armGetSystemTick();
214 #elif defined(EMSCRIPTEN)
215    time_ticks = emscripten_get_now() * 1000;
216 #endif
217
218    return time_ticks;
219 }
220
221 /**
222  * cpu_features_get_time_usec:
223  *
224  * Gets time in microseconds.
225  *
226  * @return Time in microseconds.
227  **/
228 retro_time_t cpu_features_get_time_usec(void)
229 {
230 #if defined(_WIN32)
231    static LARGE_INTEGER freq;
232    LARGE_INTEGER count;
233
234    /* Frequency is guaranteed to not change. */
235    if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
236       return 0;
237
238    if (!QueryPerformanceCounter(&count))
239       return 0;
240    return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);
241 #elif defined(__PSL1GHT__)
242    return sysGetSystemTime();
243 #elif !defined(__PSL1GHT__) && defined(__PS3__)
244    return sys_time_get_system_time();
245 #elif defined(GEKKO)
246    return ticks_to_microsecs(gettime());
247 #elif defined(WIIU)
248    return ticks_to_us(OSGetSystemTime());
249 #elif defined(SWITCH) || defined(HAVE_LIBNX)
250    return (svcGetSystemTick() * 10) / 192;
251 #elif defined(_3DS)
252    return osGetTime() * 1000;
253 #elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
254    struct timespec tv;
255    if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
256       return 0;
257    return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
258 #elif defined(EMSCRIPTEN)
259    return emscripten_get_now() * 1000;
260 #elif defined(PS2)
261    return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;
262 #elif defined(VITA) || defined(PSP)
263    return sceKernelGetSystemTimeWide();
264 #elif defined(DJGPP)
265    return uclock() * 1000000LL / UCLOCKS_PER_SEC;
266 #elif defined(ORBIS)
267    return sceKernelGetProcessTime();
268 #else
269 #error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
270 #endif
271 }
272
273 #if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)
274 #define CPU_X86
275 #endif
276
277 #if defined(_MSC_VER) && !defined(_XBOX)
278 #if (_MSC_VER > 1310)
279 #include <intrin.h>
280 #endif
281 #endif
282
283 #if defined(CPU_X86) && !defined(__MACH__)
284 void x86_cpuid(int func, int flags[4])
285 {
286    /* On Android, we compile RetroArch with PIC, and we
287     * are not allowed to clobber the ebx register. */
288 #ifdef __x86_64__
289 #define REG_b "rbx"
290 #define REG_S "rsi"
291 #else
292 #define REG_b "ebx"
293 #define REG_S "esi"
294 #endif
295
296 #if defined(__GNUC__)
297    __asm__ volatile (
298          "mov %%" REG_b ", %%" REG_S "\n"
299          "cpuid\n"
300          "xchg %%" REG_b ", %%" REG_S "\n"
301          : "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
302          : "a"(func));
303 #elif defined(_MSC_VER)
304    __cpuid(flags, func);
305 #else
306 #ifndef NDEBUG
307    printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
308 #endif
309    memset(flags, 0, 4 * sizeof(int));
310 #endif
311 }
312
313 /* Only runs on i686 and above. Needs to be conditionally run. */
314 static uint64_t xgetbv_x86(uint32_t idx)
315 {
316 #if defined(__GNUC__)
317    uint32_t eax, edx;
318    __asm__ volatile (
319          /* Older GCC versions (Apple's GCC for example) do
320           * not understand xgetbv instruction.
321           * Stamp out the machine code directly.
322           */
323          ".byte 0x0f, 0x01, 0xd0\n"
324          : "=a"(eax), "=d"(edx) : "c"(idx));
325    return ((uint64_t)edx << 32) | eax;
326 #elif _MSC_FULL_VER >= 160040219
327    /* Intrinsic only works on 2010 SP1 and above. */
328    return _xgetbv(idx);
329 #else
330 #ifndef NDEBUG
331    printf("Unknown compiler. Cannot check xgetbv bits.\n");
332 #endif
333    return 0;
334 #endif
335 }
336 #endif
337
338 #if defined(__ARM_NEON__)
339 #if defined(__arm__)
340 static void arm_enable_runfast_mode(void)
341 {
342    /* RunFast mode. Enables flush-to-zero and some
343     * floating point optimizations. */
344    static const unsigned x = 0x04086060;
345    static const unsigned y = 0x03000000;
346    int r;
347    __asm__ volatile(
348          "fmrx  %0, fpscr   \n\t" /* r0 = FPSCR */
349          "and   %0, %0, %1  \n\t" /* r0 = r0 & 0x04086060 */
350          "orr   %0, %0, %2  \n\t" /* r0 = r0 | 0x03000000 */
351          "fmxr  fpscr, %0   \n\t" /* FPSCR = r0 */
352          : "=r"(r)
353          : "r"(x), "r"(y)
354         );
355 }
356 #endif
357 #endif
358
359 #if defined(__linux__) && !defined(CPU_X86)
360 static unsigned char check_arm_cpu_feature(const char* feature)
361 {
362    char line[1024];
363    unsigned char status = 0;
364    RFILE *fp = filestream_open("/proc/cpuinfo",
365          RETRO_VFS_FILE_ACCESS_READ,
366          RETRO_VFS_FILE_ACCESS_HINT_NONE);
367
368    if (!fp)
369       return 0;
370
371    while (filestream_gets(fp, line, sizeof(line)))
372    {
373       if (strncmp(line, "Features\t: ", 11))
374          continue;
375
376       if (strstr(line + 11, feature))
377          status = 1;
378
379       break;
380    }
381
382    filestream_close(fp);
383
384    return status;
385 }
386
387 #if !defined(_SC_NPROCESSORS_ONLN)
388 /**
389  * parse_decimal:
390  *
391  * Parse an decimal integer starting from 'input', but not going further
392  * than 'limit'. Return the value into '*result'.
393  *
394  * NOTE: Does not skip over leading spaces, or deal with sign characters.
395  * NOTE: Ignores overflows.
396  *
397  * The function returns NULL in case of error (bad format), or the new
398  * position after the decimal number in case of success (which will always
399  * be <= 'limit').
400  *
401  * Leaf function.
402  **/
403 static const char *parse_decimal(const char* input,
404       const char* limit, int* result)
405 {
406     const char* p = input;
407     int       val = 0;
408
409     while (p < limit)
410     {
411         int d = (*p - '0');
412         if ((unsigned)d >= 10U)
413             break;
414         val = val*10 + d;
415         p++;
416     }
417     if (p == input)
418         return NULL;
419
420     *result = val;
421     return p;
422 }
423
424 /**
425  * cpulist_parse:
426  * Parse a textual list of cpus and store the result inside a CpuList object.
427  * Input format is the following:
428  * - comma-separated list of items (no spaces)
429  * - each item is either a single decimal number (cpu index), or a range made
430  *   of two numbers separated by a single dash (-). Ranges are inclusive.
431  *
432  * Examples:   0
433  *             2,4-127,128-143
434  *             0-1
435  **/
436 static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
437 {
438    const char* p   = (const char*)buf;
439    const char* end = p + length;
440
441    /* NOTE: the input line coming from sysfs typically contains a
442     * trailing newline, so take care of it in the code below
443     */
444    while (p < end && *p != '\n')
445    {
446       int val, start_value, end_value;
447       /* Find the end of current item, and put it into 'q' */
448       const char *q = (const char*)memchr(p, ',', end-p);
449
450       if (!q)
451          q = end;
452
453       /* Get first value */
454       if (!(p = parse_decimal(p, q, &start_value)))
455          return;
456
457       end_value = start_value;
458
459       /* If we're not at the end of the item, expect a dash and
460        * and integer; extract end value.
461        */
462       if (p < q && *p == '-')
463       {
464          if (!(p = parse_decimal(p+1, q, &end_value)))
465             return;
466       }
467
468       /* Set bits CPU list bits */
469       for (val = start_value; val <= end_value; val++)
470       {
471          if ((unsigned)val < 32)
472             list->mask |= (uint32_t)(UINT32_C(1) << val);
473       }
474
475       /* Jump to next item */
476       p = q;
477       if (p < end)
478          p++;
479    }
480 }
481
482 /**
483  * cpulist_read_from:
484  *
485  * Read a CPU list from one sysfs file
486  **/
487 static void cpulist_read_from(CpuList* list, const char* filename)
488 {
489    ssize_t length;
490    char *buf  = NULL;
491
492    list->mask = 0;
493
494    if (filestream_read_file(filename, (void**)&buf, &length) != 1)
495       return;
496
497    cpulist_parse(list, &buf, length);
498    if (buf)
499       free(buf);
500    buf = NULL;
501 }
502 #endif
503
504 #endif
505
506 /**
507  * cpu_features_get_core_amount:
508  *
509  * Gets the amount of available CPU cores.
510  *
511  * @return Amount of CPU cores available.
512  **/
513 unsigned cpu_features_get_core_amount(void)
514 {
515 #if defined(_WIN32) && !defined(_XBOX)
516    /* Win32 */
517    SYSTEM_INFO sysinfo;
518 #if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
519    GetNativeSystemInfo(&sysinfo);
520 #else
521    GetSystemInfo(&sysinfo);
522 #endif
523    return sysinfo.dwNumberOfProcessors;
524 #elif defined(GEKKO)
525    return 1;
526 #elif defined(PSP) || defined(PS2)
527    return 1;
528 #elif defined(__PSL1GHT__) || !defined(__PSL1GHT__) && defined(__PS3__)
529    return 1; /* Only one PPU, SPUs don't really count */
530 #elif defined(VITA)
531    return 4;
532 #elif defined(HAVE_LIBNX) || defined(SWITCH)
533    return 4;
534 #elif defined(_3DS)
535    u8 device_model = 0xFF;
536    CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
537    switch (device_model)
538    {
539                 case 0:
540                 case 1:
541                 case 3:
542                         /*Old 3/2DS*/
543                         return 2;
544
545                 case 2:
546                 case 4:
547                 case 5:
548                         /*New 3/2DS*/
549                         return 4;
550
551                 default:
552                         /*Unknown Device Or Check Failed*/
553                         break;
554    }
555    return 1;
556 #elif defined(WIIU)
557    return 3;
558 #elif defined(_SC_NPROCESSORS_ONLN)
559    /* Linux, most UNIX-likes. */
560    long ret = sysconf(_SC_NPROCESSORS_ONLN);
561    if (ret <= 0)
562       return (unsigned)1;
563    return (unsigned)ret;
564 #elif defined(BSD) || defined(__APPLE__)
565    /* BSD */
566    /* Copypasta from stackoverflow, dunno if it works. */
567    int num_cpu = 0;
568    int mib[4];
569    size_t len = sizeof(num_cpu);
570
571    mib[0] = CTL_HW;
572    mib[1] = HW_AVAILCPU;
573    sysctl(mib, 2, &num_cpu, &len, NULL, 0);
574    if (num_cpu < 1)
575    {
576       mib[1] = HW_NCPU;
577       sysctl(mib, 2, &num_cpu, &len, NULL, 0);
578       if (num_cpu < 1)
579          num_cpu = 1;
580    }
581    return num_cpu;
582 #elif defined(__linux__)
583    CpuList  cpus_present[1];
584    CpuList  cpus_possible[1];
585    int amount = 0;
586
587    cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
588    cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
589
590    /* Compute the intersection of both sets to get the actual number of
591     * CPU cores that can be used on this device by the kernel.
592     */
593    cpus_present->mask &= cpus_possible->mask;
594    amount              = __builtin_popcount(cpus_present->mask);
595
596    if (amount == 0)
597       return 1;
598    return amount;
599 #elif defined(_XBOX360)
600    return 3;
601 #else
602    /* No idea, assume single core. */
603    return 1;
604 #endif
605 }
606
607 /* According to http://en.wikipedia.org/wiki/CPUID */
608 #define VENDOR_INTEL_b  0x756e6547
609 #define VENDOR_INTEL_c  0x6c65746e
610 #define VENDOR_INTEL_d  0x49656e69
611
612 /**
613  * cpu_features_get:
614  *
615  * Gets CPU features..
616  *
617  * @return Bitmask of all CPU features available.
618  **/
619 uint64_t cpu_features_get(void)
620 {
621    uint64_t cpu        = 0;
622 #if defined(CPU_X86) && !defined(__MACH__)
623    int vendor_is_intel = 0;
624    const int avx_flags = (1 << 27) | (1 << 28);
625 #endif
626 #if defined(__MACH__)
627    size_t len          = sizeof(size_t);
628
629    if (sysctlbyname("hw.optional.floatingpoint", NULL, &len, NULL, 0) == 0)
630       cpu |= RETRO_SIMD_CMOV;
631
632 #if defined(CPU_X86)
633    len            = sizeof(size_t);
634    if (sysctlbyname("hw.optional.mmx", NULL, &len, NULL, 0) == 0)
635       cpu |= RETRO_SIMD_MMX | RETRO_SIMD_MMXEXT;
636
637    len            = sizeof(size_t);
638    if (sysctlbyname("hw.optional.sse", NULL, &len, NULL, 0) == 0)
639       cpu |= RETRO_SIMD_SSE;
640
641    len            = sizeof(size_t);
642    if (sysctlbyname("hw.optional.sse2", NULL, &len, NULL, 0) == 0)
643       cpu |= RETRO_SIMD_SSE2;
644
645    len            = sizeof(size_t);
646    if (sysctlbyname("hw.optional.sse3", NULL, &len, NULL, 0) == 0)
647       cpu |= RETRO_SIMD_SSE3;
648
649    len            = sizeof(size_t);
650    if (sysctlbyname("hw.optional.supplementalsse3", NULL, &len, NULL, 0) == 0)
651       cpu |= RETRO_SIMD_SSSE3;
652
653    len            = sizeof(size_t);
654    if (sysctlbyname("hw.optional.sse4_1", NULL, &len, NULL, 0) == 0)
655       cpu |= RETRO_SIMD_SSE4;
656
657    len            = sizeof(size_t);
658    if (sysctlbyname("hw.optional.sse4_2", NULL, &len, NULL, 0) == 0)
659       cpu |= RETRO_SIMD_SSE42;
660
661    len            = sizeof(size_t);
662    if (sysctlbyname("hw.optional.aes", NULL, &len, NULL, 0) == 0)
663       cpu |= RETRO_SIMD_AES;
664
665    len            = sizeof(size_t);
666    if (sysctlbyname("hw.optional.avx1_0", NULL, &len, NULL, 0) == 0)
667       cpu |= RETRO_SIMD_AVX;
668
669    len            = sizeof(size_t);
670    if (sysctlbyname("hw.optional.avx2_0", NULL, &len, NULL, 0) == 0)
671       cpu |= RETRO_SIMD_AVX2;
672
673    len            = sizeof(size_t);
674    if (sysctlbyname("hw.optional.altivec", NULL, &len, NULL, 0) == 0)
675       cpu |= RETRO_SIMD_VMX;
676
677 #else
678    len            = sizeof(size_t);
679    if (sysctlbyname("hw.optional.neon", NULL, &len, NULL, 0) == 0)
680       cpu |= RETRO_SIMD_NEON;
681
682    len            = sizeof(size_t);
683    if (sysctlbyname("hw.optional.neon_fp16", NULL, &len, NULL, 0) == 0)
684       cpu |= RETRO_SIMD_VFPV3;
685
686    len            = sizeof(size_t);
687    if (sysctlbyname("hw.optional.neon_hpfp", NULL, &len, NULL, 0) == 0)
688       cpu |= RETRO_SIMD_VFPV4;
689 #endif
690 #elif defined(_XBOX1)
691    cpu |= RETRO_SIMD_MMX | RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
692 #elif defined(CPU_X86)
693    unsigned max_flag   = 0;
694    int flags[4];
695    int vendor_shuffle[3];
696    char vendor[13];
697    x86_cpuid(0, flags);
698    vendor_shuffle[0] = flags[1];
699    vendor_shuffle[1] = flags[3];
700    vendor_shuffle[2] = flags[2];
701
702    vendor[0]         = '\0';
703    memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));
704
705    /* printf("[CPUID]: Vendor: %s\n", vendor); */
706
707    vendor_is_intel = (
708          flags[1] == VENDOR_INTEL_b &&
709          flags[2] == VENDOR_INTEL_c &&
710          flags[3] == VENDOR_INTEL_d);
711
712    max_flag = flags[0];
713    if (max_flag < 1) /* Does CPUID not support func = 1? (unlikely ...) */
714       return 0;
715
716    x86_cpuid(1, flags);
717
718    if (flags[3] & (1 << 15))
719       cpu |= RETRO_SIMD_CMOV;
720
721    if (flags[3] & (1 << 23))
722       cpu |= RETRO_SIMD_MMX;
723
724    /* SSE also implies MMXEXT (according to FFmpeg source). */
725    if (flags[3] & (1 << 25))
726       cpu |= RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
727
728    if (flags[3] & (1 << 26))
729       cpu |= RETRO_SIMD_SSE2;
730
731    if (flags[2] & (1 << 0))
732       cpu |= RETRO_SIMD_SSE3;
733
734    if (flags[2] & (1 << 9))
735       cpu |= RETRO_SIMD_SSSE3;
736
737    if (flags[2] & (1 << 19))
738       cpu |= RETRO_SIMD_SSE4;
739
740    if (flags[2] & (1 << 20))
741       cpu |= RETRO_SIMD_SSE42;
742
743    if ((flags[2] & (1 << 23)))
744       cpu |= RETRO_SIMD_POPCNT;
745
746    if (vendor_is_intel && (flags[2] & (1 << 22)))
747       cpu |= RETRO_SIMD_MOVBE;
748
749    if (flags[2] & (1 << 25))
750       cpu |= RETRO_SIMD_AES;
751
752    /* Must only perform xgetbv check if we have
753     * AVX CPU support (guaranteed to have at least i686). */
754    if (((flags[2] & avx_flags) == avx_flags)
755          && ((xgetbv_x86(0) & 0x6) == 0x6))
756       cpu |= RETRO_SIMD_AVX;
757
758    if (max_flag >= 7)
759    {
760       x86_cpuid(7, flags);
761       if (flags[1] & (1 << 5))
762          cpu |= RETRO_SIMD_AVX2;
763    }
764
765    x86_cpuid(0x80000000, flags);
766    max_flag = flags[0];
767    if (max_flag >= 0x80000001u)
768    {
769       x86_cpuid(0x80000001, flags);
770       if (flags[3] & (1 << 23))
771          cpu |= RETRO_SIMD_MMX;
772       if (flags[3] & (1 << 22))
773          cpu |= RETRO_SIMD_MMXEXT;
774    }
775 #elif defined(__linux__)
776    if (check_arm_cpu_feature("neon"))
777    {
778       cpu |= RETRO_SIMD_NEON;
779 #if defined(__ARM_NEON__) && defined(__arm__)
780       arm_enable_runfast_mode();
781 #endif
782    }
783
784    if (check_arm_cpu_feature("vfpv3"))
785       cpu |= RETRO_SIMD_VFPV3;
786
787    if (check_arm_cpu_feature("vfpv4"))
788       cpu |= RETRO_SIMD_VFPV4;
789
790    if (check_arm_cpu_feature("asimd"))
791    {
792       cpu |= RETRO_SIMD_ASIMD;
793 #ifdef __ARM_NEON__
794       cpu |= RETRO_SIMD_NEON;
795 #if defined(__arm__)
796       arm_enable_runfast_mode();
797 #endif
798 #endif
799    }
800
801 #if 0
802     check_arm_cpu_feature("swp");
803     check_arm_cpu_feature("half");
804     check_arm_cpu_feature("thumb");
805     check_arm_cpu_feature("fastmult");
806     check_arm_cpu_feature("vfp");
807     check_arm_cpu_feature("edsp");
808     check_arm_cpu_feature("thumbee");
809     check_arm_cpu_feature("tls");
810     check_arm_cpu_feature("idiva");
811     check_arm_cpu_feature("idivt");
812 #endif
813
814 #elif defined(__ARM_NEON__)
815    cpu |= RETRO_SIMD_NEON;
816 #if defined(__arm__)
817    arm_enable_runfast_mode();
818 #endif
819 #elif defined(__ALTIVEC__)
820    cpu |= RETRO_SIMD_VMX;
821 #elif defined(XBOX360)
822    cpu |= RETRO_SIMD_VMX128;
823 #elif defined(PSP) || defined(PS2)
824    cpu |= RETRO_SIMD_VFPU;
825 #elif defined(GEKKO)
826    cpu |= RETRO_SIMD_PS;
827 #endif
828
829    return cpu;
830 }
831
832 void cpu_features_get_model_name(char *name, int len)
833 {
834 #if defined(CPU_X86) && !defined(__MACH__)
835    union {
836       int32_t i[4];
837       uint32_t u[4];
838       uint8_t s[16];
839    } flags;
840    int i, j;
841    int pos = 0;
842    bool start = false;
843
844    if (!name)
845       return;
846
847    x86_cpuid(0x80000000, flags.i);
848
849    /* Check for additional cpuid attributes availability */
850    if (flags.u[0] < 0x80000004)
851       return;
852
853    for (i = 0; i < 3; i++)
854    {
855       memset(flags.i, 0, sizeof(flags.i));
856       x86_cpuid(0x80000002 + i, flags.i);
857
858       for (j = 0; j < (int)sizeof(flags.s); j++)
859       {
860          if (!start && flags.s[j] == ' ')
861             continue;
862          else
863             start = true;
864
865          if (pos == len - 1)
866          {
867             /* truncate if we ran out of room */
868             name[pos] = '\0';
869             goto end;
870          }
871
872          name[pos++] = flags.s[j];
873       }
874    }
875 end:
876    /* terminate our string */
877    if (pos < len)
878       name[pos] = '\0';
879 #elif defined(__MACH__)
880    if (!name)
881       return;
882    {
883       size_t len_size = len;
884       sysctlbyname("machdep.cpu.brand_string", name, &len_size, NULL, 0);
885    }
886 #elif defined(__linux__)
887    if (!name)
888       return;
889    {
890       char *model_name, line[128];
891       RFILE *fp = filestream_open("/proc/cpuinfo",
892             RETRO_VFS_FILE_ACCESS_READ,
893             RETRO_VFS_FILE_ACCESS_HINT_NONE);
894
895       if (!fp)
896          return;
897
898       while (filestream_gets(fp, line, sizeof(line)))
899       {
900          if (strncmp(line, "model name", 10))
901             continue;
902
903          if ((model_name = strstr(line + 10, ": ")))
904          {
905             model_name += 2;
906             strncpy(name, model_name, len);
907             name[len - 1] = '\0';
908          }
909
910          break;
911       }
912
913       filestream_close(fp);
914    }
915 #else
916    if (!name)
917       return;
918    return;
919 #endif
920 }