Andrew Geissler | 84ad7c5 | 2020-06-27 00:00:16 -0500 | [diff] [blame] | 1 | import argparse |
| 2 | import libfdt |
| 3 | import os |
| 4 | import sys |
| 5 | |
| 6 | # Format: FEATURE : (dtb property, condition_operator, condition_value) |
| 7 | # If dtb property is None, then the item is always on |
| 8 | # |
| 9 | # If the condition_operator is None, then enable if it exists for existance |
| 10 | # |
| 11 | # If the condition_operator is '!', and condition_value is None then enable if |
| 12 | # if is not defined |
| 13 | # |
| 14 | # Otherwise 'condition' and value are evaluated by type. |
Andrew Geissler | a9ff2b3 | 2020-10-16 10:11:54 -0500 | [diff] [blame] | 15 | # |
| 16 | # If the condition is = then any value of condition_values will set it |
| 17 | # If the condition is ! then no value of condition_values will set it |
Andrew Geissler | 84ad7c5 | 2020-06-27 00:00:16 -0500 | [diff] [blame] | 18 | |
| 19 | microblaze_tune_features = { |
| 20 | 'microblaze' : (None, None, None), |
| 21 | 'bigendian': ('xlnx,endianness', '!', 1), |
| 22 | '64-bit' : ('xlnx,data-size', '=', 64), |
| 23 | 'barrel-shift': ('xlnx,use-barrel', '=', 1), |
Andrew Geissler | a9ff2b3 | 2020-10-16 10:11:54 -0500 | [diff] [blame] | 24 | 'pattern-compare': ('xlnx,use-pcmp-instr', '=', 1), |
Andrew Geissler | 84ad7c5 | 2020-06-27 00:00:16 -0500 | [diff] [blame] | 25 | 'reorder' : ('xlnx,use-reorder-instr', '!', 0), |
| 26 | 'frequency-optimized': ('xlnx,area-optimized', '=', 2), |
| 27 | 'multiply-low': ('xlnx,use-hw-mul', '=', 1), |
| 28 | 'multiply-high': ('xlnx,use-hw-mul', '=', 2), |
Andrew Geissler | a9ff2b3 | 2020-10-16 10:11:54 -0500 | [diff] [blame] | 29 | 'divide-hard': ('xlnx,use-div', '=', 1), |
Andrew Geissler | 84ad7c5 | 2020-06-27 00:00:16 -0500 | [diff] [blame] | 30 | 'fpu-soft': ('xlnx,use-fpu', '!', [1,2]), |
| 31 | 'fpu-hard': ('xlnx,use-fpu', '=', 1), |
| 32 | 'fpu-hard-extended':('xlnx,use-fpu', '=', 2), |
| 33 | } |
| 34 | |
| 35 | def processProperties(fdt, node): |
| 36 | TUNE_FEATURES = [] |
| 37 | |
| 38 | for feature in microblaze_tune_features: |
| 39 | (property, cop, cvalue) = microblaze_tune_features[feature] |
| 40 | |
| 41 | if not property: |
| 42 | TUNE_FEATURES.append(feature) |
| 43 | |
| 44 | # Special processing to get the version |
| 45 | if feature == "microblaze": |
| 46 | ver = microblazeVersion(fdt, node) |
| 47 | if ver: |
| 48 | TUNE_FEATURES.append(ver) |
| 49 | continue |
| 50 | |
| 51 | prop_value = fdt.getprop( node, property, libfdt.QUIET_NOTFOUND) |
| 52 | |
| 53 | if not prop_value or prop_value == -1: |
| 54 | if cop == '!': |
| 55 | if not cvalue: |
| 56 | TUNE_FEATURES.append(ver) |
| 57 | continue |
| 58 | continue |
| 59 | |
| 60 | # If no operator |
| 61 | if not cop or (cop == '=' and not cvalue): |
| 62 | TUNE_FEATURES.append(feature) |
| 63 | continue |
| 64 | |
| 65 | ctype = type(cvalue) |
| 66 | if ctype == type(list()): |
| 67 | val_list = cvalue |
| 68 | else: |
| 69 | val_list = [ cvalue ] |
| 70 | |
| 71 | result = False |
| 72 | for value in val_list: |
| 73 | ctype = type(value) |
| 74 | if ctype == type(int()): |
| 75 | val = prop_value.as_uint32() |
| 76 | else: |
| 77 | raise TypeError('Unknown type %s' % ctype) |
| 78 | |
Andrew Geissler | a9ff2b3 | 2020-10-16 10:11:54 -0500 | [diff] [blame] | 79 | if value == val: |
| 80 | result = True |
| 81 | break |
| 82 | else: |
| 83 | result = False |
Andrew Geissler | 84ad7c5 | 2020-06-27 00:00:16 -0500 | [diff] [blame] | 84 | |
Andrew Geissler | a9ff2b3 | 2020-10-16 10:11:54 -0500 | [diff] [blame] | 85 | if (cop == '!' and result == False) or \ |
| 86 | (cop == '=' and result == True): |
Andrew Geissler | 84ad7c5 | 2020-06-27 00:00:16 -0500 | [diff] [blame] | 87 | TUNE_FEATURES.append(feature) |
| 88 | |
| 89 | return TUNE_FEATURES |
| 90 | |
| 91 | def microblazeVersion(fdt, node): |
| 92 | version = None |
| 93 | |
| 94 | val = fdt.getprop( node, 'model', libfdt.QUIET_NOTFOUND) |
| 95 | |
| 96 | if val and val != -1: |
| 97 | val = fdt.getprop( node, 'model' ).as_str() |
| 98 | version = val[val.find('microblaze,') + 11:] |
| 99 | |
| 100 | if version.startswith('8'): |
| 101 | # Strip 8.xx.y, to just 8.xx |
| 102 | v = version.split('.') |
| 103 | version = '.'.join(v[0:2]) |
| 104 | |
| 105 | version = 'v' + version |
| 106 | |
| 107 | return version |
| 108 | |
| 109 | def MicroblazeConfig(dtbfile, out): |
| 110 | fdt = libfdt.Fdt(open(dtbfile, mode='rb').read()) |
| 111 | |
| 112 | cpu = -1 |
| 113 | while (True): |
| 114 | cpu = cpu + 1 |
| 115 | try: |
| 116 | node = fdt.path_offset('/cpus/cpu@%d' % cpu) |
| 117 | |
| 118 | try: |
| 119 | prop = fdt.getprop( node, 'compatible' ) |
| 120 | |
| 121 | prop_val = prop[:-1].decode('utf-8').split('\x00') |
| 122 | |
| 123 | microblaze = False |
| 124 | for val in prop_val: |
| 125 | if "microblaze" in val: |
| 126 | microblaze = True |
| 127 | break |
| 128 | |
| 129 | if not microblaze: |
| 130 | continue |
| 131 | |
| 132 | # Construct TUNE_FEATURE here |
| 133 | TUNE_FEATURES = processProperties(fdt, node) |
| 134 | |
| 135 | out.write('AVAILTUNES += "microblaze-cpu%s"\n' % (cpu)) |
| 136 | out.write('TUNE_FEATURES_tune-microblaze-cpu%s = "%s"\n' % (cpu, ' '.join(TUNE_FEATURES))) |
| 137 | out.write('PACKAGE_EXTRA_ARCHS_tune-microblaze-cpu%s = "${TUNE_PKGARCH}"\n' % (cpu)) |
| 138 | |
| 139 | except Exception as e: |
| 140 | sys.stderr.write("Exception looking at properties: %s\n" % e) |
| 141 | |
| 142 | continue |
| 143 | |
| 144 | except Exception as e: |
| 145 | # CPUs SHOULD be consecutive w/o gaps, so no more to search |
| 146 | break |
| 147 | |
| 148 | if __name__ == "__main__": |
| 149 | parser = argparse.ArgumentParser(description='Generate MicroBlaze TUNE_FEATURES') |
| 150 | |
| 151 | parser.add_argument('-d', '--dtb-file', action='store', |
| 152 | help='DTB file to process') |
| 153 | |
| 154 | parser.add_argument('-o', '--output', action='store', |
| 155 | help='Output file to store TUNE_FEATURE settings') |
| 156 | |
| 157 | args = parser.parse_args() |
| 158 | |
| 159 | if not args.dtb_file: |
| 160 | sys.stderr.write('ERROR: You must specify a DTB_FILE to process.\n') |
| 161 | sys.exit(1) |
| 162 | |
| 163 | outputf = sys.stdout |
| 164 | if args.output: |
| 165 | if os.path.exists(args.output): |
| 166 | sys.stderr.write('ERROR: The output file "%s" exists!\n' % args.output) |
| 167 | sys.exit(1) |
| 168 | outputf = open(args.output, 'w') |
| 169 | |
| 170 | MicroblazeConfig(args.dtb_file, outputf) |