#!/usr/bin/env python # # Copyright 2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # # GNU Radio 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 3, or (at your option) # any later version. # # GNU Radio 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 GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # from xml.dom import minidom HEADER_TEMPL = """\ /*this file is auto_generated by volk_register.py*/ #include #include struct VOLK_CPU volk_cpu; #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) # define VOLK_CPU_x86 #endif #if defined(VOLK_CPU_x86) //implement get cpuid for gcc compilers using a copy of cpuid.h #if defined(__GNUC__) #include #define cpuid_x86(op, r) __get_cpuid(op, (unsigned int *)r+0, (unsigned int *)r+1, (unsigned int *)r+2, (unsigned int *)r+3) /* Return Intel AVX extended CPU capabilities register. * This function will bomb on non-AVX-capable machines, so * check for AVX capability before executing. */ #if __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 4 static inline unsigned long long _xgetbv(unsigned int index){ unsigned int eax, edx; __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); return ((unsigned long long)edx << 32) | eax; } #define __xgetbv() _xgetbv(0) #else #define __xgetbv() 0 #endif //implement get cpuid for MSVC compilers using __cpuid intrinsic #elif defined(_MSC_VER) #include #define cpuid_x86(op, r) __cpuid(r, op) #if defined(_XCR_XFEATURE_ENABLED_MASK) #define __xgetbv() _xgetbv(_XCR_XFEATURE_ENABLED_MASK) #else #define __xgetbv() 0 #endif #else #error "A get cpuid for volk is not available on this compiler..." #endif static inline unsigned int cpuid_eax(unsigned int op) { int regs[4]; cpuid_x86 (op, regs); return regs[0]; } static inline unsigned int cpuid_ebx(unsigned int op) { int regs[4]; cpuid_x86 (op, regs); return regs[1]; } static inline unsigned int cpuid_ecx(unsigned int op) { int regs[4]; cpuid_x86 (op, regs); return regs[2]; } static inline unsigned int cpuid_edx(unsigned int op) { int regs[4]; cpuid_x86 (op, regs); return regs[3]; } static inline unsigned int xgetbv(void) { //check to make sure that xgetbv is enabled in OS int xgetbv_enabled = cpuid_ecx(1) >> 27 & 0x01; if(xgetbv_enabled == 0) return 0; return __xgetbv(); } #endif """ def make_cpuid_c(dom) : tempstring = HEADER_TEMPL; for domarch in dom: if str(domarch.attributes["type"].value) == "x86": if "no_test" in domarch.attributes.keys(): no_test = str(domarch.attributes["no_test"].value); if no_test == "true": no_test = True; else: no_test = False; else: no_test = False; arch = str(domarch.attributes["name"].value) op = domarch.getElementsByTagName("op") if op: op = str(op[0].firstChild.data) reg = domarch.getElementsByTagName("reg") if reg: reg = str(reg[0].firstChild.data) shift = domarch.getElementsByTagName("shift") if shift: shift = str(shift[0].firstChild.data) val = domarch.getElementsByTagName("val") if val: val = str(val[0].firstChild.data) check = domarch.getElementsByTagName("check") if check: check = str(check[0].firstChild.data) checkval = domarch.getElementsByTagName("checkval") if checkval: checkval = str(checkval[0].firstChild.data) if no_test: tempstring = tempstring + """\ int i_can_has_%s () { #if defined(VOLK_CPU_x86) return 1; #else return 0; #endif } """ % (arch) elif op == "1": tempstring = tempstring + """\ int i_can_has_%s () { #if defined(VOLK_CPU_x86) unsigned int e%sx = cpuid_e%sx (%s); int hwcap = (((e%sx >> %s) & 1) == %s); """ % (arch, reg, reg, op, reg, shift, val) if check and checkval: tempstring += """\ if (hwcap == 0) return 0; hwcap &= (%s() == %s); """ % (check, checkval) tempstring += """\ return hwcap; #else return 0; #endif } """ elif op == "0x80000001": tempstring = tempstring + """\ int i_can_has_%s () { #if defined(VOLK_CPU_x86) unsigned int extended_fct_count = cpuid_eax(0x80000000); if (extended_fct_count < 0x80000001) return %s^1; unsigned int extended_features = cpuid_e%sx (%s); return ((extended_features >> %s) & 1) == %s; #else return 0; #endif } """ % (arch, val, reg, op, shift, val) elif str(domarch.attributes["type"].value) == "powerpc": arch = str(domarch.attributes["name"].value); tempstring = tempstring + """\ int i_can_has_%s () { #ifdef __PPC__ return 1; #else return 0; #endif } """ % (arch) elif str(domarch.attributes["type"].value) == "arm": arch = str(domarch.attributes["name"].value); tempstring = tempstring + """\ #if defined(__arm__) && defined(__linux__) #include #include #include #define LOOK_FOR_NEON #endif int i_can_has_%s () { //it's linux-specific, but if you're compiling libvolk for NEON //on Windows you have other problems #ifdef LOOK_FOR_NEON FILE *auxvec_f; unsigned long auxvec[2]; unsigned int found_neon = 0; auxvec_f = fopen("/proc/self/auxv", "rb"); if(!auxvec_f) return 0; //so auxv is basically 32b of ID and 32b of value //so it goes like this while(!found_neon && auxvec_f) { fread(auxvec, sizeof(unsigned long), 2, auxvec_f); if((auxvec[0] == AT_HWCAP) && (auxvec[1] & HWCAP_NEON)) found_neon = 1; } fclose(auxvec_f); return found_neon; #else return 0; #endif } """ % (arch) elif str(domarch.attributes["type"].value) == "all": arch = str(domarch.attributes["name"].value); tempstring = tempstring + """\ int i_can_has_%s () { return 1; } """ % (arch) else: arch = str(domarch.attributes["name"].value); tempstring = tempstring + """\ int i_can_has_%s () { return 0; } """ % (arch) tempstring = tempstring + "void volk_cpu_init() {\n"; for domarch in dom: arch = str(domarch.attributes["name"].value); tempstring = tempstring + " volk_cpu.has_" + arch + " = &i_can_has_" + arch + ";\n" tempstring = tempstring + "}\n\n" tempstring = tempstring + "unsigned int volk_get_lvarch() {\n"; tempstring = tempstring + " unsigned int retval = 0;\n" tempstring = tempstring + " volk_cpu_init();\n" for domarch in dom: arch = str(domarch.attributes["name"].value); tempstring = tempstring + " retval += volk_cpu.has_" + arch + "() << LV_" + arch.swapcase() + ";\n" tempstring = tempstring + " return retval;\n" tempstring = tempstring + "}\n\n" return tempstring;