Source code for envi.bits

"""
A file full of bit twidling helpers
"""

import struct

MAX_WORD = 8 # Dont have any more than 64 bit archs

# Masks to use for unsigned anding to size
u_maxes = [ (2 ** (8*i)) - 1 for i in range(MAX_WORD+1) ]
u_maxes[0] = 0 # powers of 0 are 1, but we need 0

# Masks of just the sign bit for different sizes
sign_bits = [ (2 ** (8*i)) >> 1 for i in range(MAX_WORD+1) ]
sign_bits[0] = 0 # powers of 0 are 1, but we need 0

# Max *signed* masks (all but top bit )
s_maxes = [ u_maxes[i] ^ sign_bits[i] for i in range(len(u_maxes))]
s_maxes[0] = 0

# bit width masks 
b_masks = [ (2**i)-1 for i in range(MAX_WORD*8) ]
b_masks[0] = 0

[docs]def unsigned(value, size): """ Make a value unsigned based on it's size. """ # In python "&" will do abs value return value & u_maxes[size]
[docs]def signed(value, size): """ Make a value signed based on it's size. """ x = unsigned(value, size) if x & sign_bits[size]: x = (x - u_maxes[size]) - 1 return x
[docs]def is_signed(value, size): x = unsigned(value, size) return bool(x & sign_bits[size])
[docs]def sign_extend(value, cursize, newsize): """ Take a value and extend it's size filling in the space with the value of the high order bit. """ x = unsigned(value, cursize) if cursize != newsize: # Test for signed w/o the call if x & sign_bits[cursize]: delta = newsize - cursize highbits = u_maxes[delta] x |= highbits << (8*cursize) return x
[docs]def is_parity(val): s = 0 while val: s ^= val & 1 val = val >> 1 return (not s)
parity_table = [] for i in range(256): parity_table.append(is_parity(i))
[docs]def is_parity_byte(bval): """ An "optimized" parity checker that looks up the index. """ return parity_table[bval & 0xff]
[docs]def lsb(value): return value & 0x1
[docs]def msb(value, size): if value & sign_bits[size]: return 1 return 0
[docs]def is_signed_overflow(value, size): max = s_maxes[size] if value > max: return True if value < -max: return True return False
[docs]def is_unsigned_carry(value, size): umax = u_maxes[size] if value > umax: return True elif value < 0: return True return False
[docs]def is_aux_carry(src, dst): # FIXME this is only how to do it for add... dst = dst & 0xf src = src & 0xf if (dst + src) > 15: return True return False
le_fmt_chars = (None,"B","<H",None,"<L",None,None,None,"<Q") be_fmt_chars = (None,"B",">H",None,">L",None,None,None,">Q")
[docs]def parsebytes(bytes, offset, size, sign=False, bigend=False): """ Mostly for pulling immediates out of strings... """ if size > 8: return slowparsebytes(bytes, offset, size, sign=sign, bigend=bigend) if bigend: f = be_fmt_chars[size] else: f = le_fmt_chars[size] if f == None: return slowparsebytes(bytes, offset, size, sign=sign, bigend=bigend) d = bytes[offset:offset+size] x = struct.unpack(f, d)[0] if sign: x = signed(x, size) return x
[docs]def slowparsebytes(bytes, offset, size, sign=False, bigend=False): if bigend: begin = offset inc = 1 else: begin = offset + (size-1) inc = -1 ret = 0 ioff = 0 for x in range(size): ret = ret << 8 ret |= ord(bytes[begin+ioff]) ioff += inc if sign: ret = signed(ret, size) return ret
[docs]def buildbytes(value, size, bigend=False): if bigend: f = be_fmt_chars[size] else: f = le_fmt_chars[size] if f == None: raise Exception("envi.bits.buildbytes needs slowbuildbytes") return struct.pack(f, value)
[docs]def byteswap(value, size): ret = 0 for i in range(size): ret |= (value >> (8*i)) & 0xff ret = ret << 8 return ret
hex_fmt = { 1:"0x%.2x", 2:"0x%.4x", 4:"0x%.8x", 8:"0x%.16x", }
[docs]def intwidth(val): if val < 0: val = abs(val) ret = 0 while val: ret += 1 val = val >> 8 return ret
[docs]def hex(value, size=None): if size == None: size = intwidth(value) fmt = hex_fmt.get(size) if fmt != None: return fmt % value x = [] while value: x.append('%.2x' % (value & 0xff)) value = value >> 8 x.reverse() return '0x%.s' % ''.join(x) return hex_fmt.get(size) % value
[docs]def binrepr(intval, bitwidth=None): ''' Return a string of one's and zero's for the given value. ''' ret = [] while intval: ret.append(str(intval & 0x1)) intval >>= 1 ret.reverse() binstr = ''.join(ret) if bitwidth != None: binstr = binstr.rjust(bitwidth, '0') return binstr
[docs]def binary(binstr): ''' Decode a binary string of 1/0's into a python number ''' x = 0 for c in binstr: x = (x << 1) + int(c) return x
[docs]def binbytes(binstr): ''' Decode a binary string of 1/0's into a python binary string. ''' if len(binstr) % 8 != 0: raise Exception('Byte padded binary strings only for now!') bytes = '' while binstr: bytes += chr( binary(binstr[:8]) ) binstr = binstr[8:] return bytes
[docs]def parsebits(bytes, offset, bitoff, bitsize): ''' Parse bitsize bits from the bit offset bitoff beginning at offset bytes. Example: ''' val = 0 cnt = 0 while cnt < bitsize: addbit = bitoff + cnt addoff = offset + (addbit / 8) modoff = addbit % 8 o = ord(bytes[addoff]) val = (val << 1) + ((o >> (7 - modoff)) & 1) cnt += 1 return val #if __name__ == '__main__': #print hex(parsebits('\x0f\x00', 0, 4, 8)) #print hex(parsebits('\x0f\x0f', 0, 4, 12)) #print hex(parsebits('\x0f\x0f\xf0', 1, 4, 4))