1# Copyright (c) 2005 The Regents of The University of Michigan 2# Copyright (c) 2010 Advanced Micro Devices, Inc. 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27# 28# Authors: Nathan Binkert 29# Gabe Black 30 31import six 32if six.PY3: 33 long = int 34 35# metric prefixes 36atto = 1.0e-18 37femto = 1.0e-15 38pico = 1.0e-12 39nano = 1.0e-9 40micro = 1.0e-6 41milli = 1.0e-3 42 43kilo = 1.0e3 44mega = 1.0e6 45giga = 1.0e9 46tera = 1.0e12 47peta = 1.0e15 48exa = 1.0e18 49 50# power of 2 prefixes 51kibi = 1024 52mebi = kibi * 1024 53gibi = mebi * 1024 54tebi = gibi * 1024 55pebi = tebi * 1024 56exbi = pebi * 1024 57 58metric_prefixes = { 59 'Ei': exbi, 60 'E': exa, 61 'Pi': pebi, 62 'P': peta, 63 'Ti': tebi, 64 'T': tera, 65 'Gi': gibi, 66 'G': giga, 67 'M': mega, 68 'ki': kibi, 69 'k': kilo, 70 'Mi': mebi, 71 'm': milli, 72 'u': micro, 73 'n': nano, 74 'p': pico, 75 'f': femto, 76 'a': atto, 77} 78 79binary_prefixes = { 80 'Ei': exbi, 81 'E' : exbi, 82 'Pi': pebi, 83 'P' : pebi, 84 'Ti': tebi, 85 'T' : tebi, 86 'Gi': gibi, 87 'G' : gibi, 88 'Mi': mebi, 89 'M' : mebi, 90 'ki': kibi, 91 'k' : kibi, 92} 93 94def assertStr(value): 95 if not isinstance(value, str): 96 raise TypeError("wrong type '%s' should be str" % type(value)) 97 98 99# memory size configuration stuff 100def toNum(value, target_type, units, prefixes, converter): 101 assertStr(value) 102 103 def convert(val): 104 try: 105 return converter(val) 106 except ValueError: 107 raise ValueError( 108 "cannot convert '%s' to %s" % (value, target_type)) 109 110 if units and not value.endswith(units): 111 units = None 112 if not units: 113 return convert(value) 114 115 value = value[:-len(units)] 116 117 prefix = next((p for p in prefixes.keys() if value.endswith(p)), None) 118 if not prefix: 119 return convert(value) 120 value = value[:-len(prefix)] 121 122 return convert(value) * prefixes[prefix] 123 124def toFloat(value, target_type='float', units=None, prefixes=[]): 125 return toNum(value, target_type, units, prefixes, float) 126 127def toMetricFloat(value, target_type='float', units=None): 128 return toFloat(value, target_type, units, metric_prefixes) 129 130def toBinaryFloat(value, target_type='float', units=None): 131 return toFloat(value, target_type, units, binary_prefixes) 132 133def toInteger(value, target_type='integer', units=None, prefixes=[]): 134 intifier = lambda x: int(x, 0) 135 return toNum(value, target_type, units, prefixes, intifier) 136 137def toMetricInteger(value, target_type='integer', units=None): 138 return toInteger(value, target_type, units, metric_prefixes) 139 140def toBinaryInteger(value, target_type='integer', units=None): 141 return toInteger(value, target_type, units, binary_prefixes) 142 143def toBool(value): 144 assertStr(value) 145 146 value = value.lower() 147 if value in ('true', 't', 'yes', 'y', '1'): 148 return True 149 if value in ('false', 'f', 'no', 'n', '0'): 150 return False 151 return result 152 153def toFrequency(value): 154 return toMetricFloat(value, 'frequency', 'Hz') 155 156def toLatency(value): 157 return toMetricFloat(value, 'latency', 's') 158 159def anyToLatency(value): 160 """result is a clock period""" 161 try: 162 return 1 / toFrequency(value) 163 except (ValueError, ZeroDivisionError): 164 pass 165 166 try: 167 return toLatency(value) 168 except ValueError: 169 pass 170 171 raise ValueError("cannot convert '%s' to clock period" % value) 172 173def anyToFrequency(value): 174 """result is a clock period""" 175 try: 176 return toFrequency(value) 177 except ValueError: 178 pass 179 180 try: 181 return 1 / toLatency(value) 182 except ValueError as ZeroDivisionError: 183 pass 184 185 raise ValueError("cannot convert '%s' to clock period" % value) 186 187def toNetworkBandwidth(value): 188 return toMetricFloat(value, 'network bandwidth', 'bps') 189 190def toMemoryBandwidth(value): 191 return toBinaryFloat(value, 'memory bandwidth', 'B/s') 192 193def toMemorySize(value): 194 return toBinaryInteger(value, 'memory size', 'B') 195 196def toIpAddress(value): 197 if not isinstance(value, str): 198 raise TypeError("wrong type '%s' should be str" % type(value)) 199 200 bytes = value.split('.') 201 if len(bytes) != 4: 202 raise ValueError('invalid ip address %s' % value) 203 204 for byte in bytes: 205 if not 0 <= int(byte) <= 0xff: 206 raise ValueError('invalid ip address %s' % value) 207 208 return (int(bytes[0]) << 24) | (int(bytes[1]) << 16) | \ 209 (int(bytes[2]) << 8) | (int(bytes[3]) << 0) 210 211def toIpNetmask(value): 212 if not isinstance(value, str): 213 raise TypeError("wrong type '%s' should be str" % type(value)) 214 215 (ip, netmask) = value.split('/') 216 ip = toIpAddress(ip) 217 netmaskParts = netmask.split('.') 218 if len(netmaskParts) == 1: 219 if not 0 <= int(netmask) <= 32: 220 raise ValueError('invalid netmask %s' % netmask) 221 return (ip, int(netmask)) 222 elif len(netmaskParts) == 4: 223 netmaskNum = toIpAddress(netmask) 224 if netmaskNum == 0: 225 return (ip, 0) 226 testVal = 0 227 for i in range(32): 228 testVal |= (1 << (31 - i)) 229 if testVal == netmaskNum: 230 return (ip, i + 1) 231 raise ValueError('invalid netmask %s' % netmask) 232 else: 233 raise ValueError('invalid netmask %s' % netmask) 234 235def toIpWithPort(value): 236 if not isinstance(value, str): 237 raise TypeError("wrong type '%s' should be str" % type(value)) 238 239 (ip, port) = value.split(':') 240 ip = toIpAddress(ip) 241 if not 0 <= int(port) <= 0xffff: 242 raise ValueError('invalid port %s' % port) 243 return (ip, int(port)) 244 245def toVoltage(value): 246 return toMetricFloat(value, 'voltage', 'V') 247 248def toCurrent(value): 249 return toMetricFloat(value, 'current', 'A') 250 251def toEnergy(value): 252 return toMetricFloat(value, 'energy', 'J') 253