-#!/usr/bin/python2.4
+#!/usr/bin/env python3
#
# Utility to decode register values
# Copyright (c) 2006 Jeremy Kerr <jk@ozlabs.org>
import os
import sys
import pprint
+import math
from pyparsing import Literal, Word, ZeroOrMore, Group, Dict, Optional, \
printables, ParseException, restOfLine
from getopt import getopt, GetoptError
# List of paths to look for configuration files. If a directory is specified,
# it will be (recursively) scanned for .conf files.
-configs = [os.path.join(os.getenv("HOME"), ".bitfields.conf"),
- os.path.join(os.getenv("HOME"), ".bitfields.d")]
+configs = ["/etc/bitfield.d", "/etc/bitfield",
+ os.path.join(os.getenv("HOME"), ".bitfield.d"),
+ os.path.join(os.getenv("HOME"), ".bitfield.conf")]
class bitfield:
- def __init__(self, start_bit, end_bit, name):
- self.start_bit = start_bit
- self.end_bit = end_bit
+ def __init__(self, bits, name):
+ self.bits = bits
self.name = name
self.values = {}
- def start_bit(self):
- return self.start_bit
-
- def end_bit(self):
- return self.end_bit
-
def width(self):
- return 1 + self.end_bit - self.start_bit
+ return len(self.bits)
def add_value(self, value, description):
- self.values[int(value)] = description
+ self.values[int(value, 0)] = description
+
+ def mask(self, reg, value):
+ ret = 0
+ out_len = len(self.bits)
+
+ if reg.bit_order == reg.bit_0_is_msb:
+ bit_pairs = zip(self.bits, range(0, out_len))
+ else:
+ bit_pairs = zip(self.bits, range(out_len - 1, -1, -1))
- def mask(self, reg_width, value):
- shift = (reg_width - 1) - self.end_bit
- return (((2 ** self.width() - 1) << (shift))
- & value) >> shift
+ for (in_bit, out_bit) in bit_pairs:
+ # shift this bit down to the LSB (and mask the rest)
+ i = (value >> (reg.width - in_bit - 1)) & 1
+ # shift back to the output position in the field
+ i <<= out_len - out_bit - 1
+ ret |= i
+ return ret
def value(self, value):
if value in self.values:
return self.values[value]
return None
- def __str__(self):
- return "[%2d:%-2d] %s 0x%x" % (int(self.start_bit),
- int(self.end_bit), self.name, self.mask())
+ @staticmethod
+ def mask_and_shift_to_bits(width, mask, shift):
+ bits = []
+ val = mask << shift
+ for i in range(0, width):
+ if mask & (1 << i):
+ bits.insert(0, width - i - 1 - shift)
+ return bits
+
+ @staticmethod
+ def mask_to_bits(width, mask):
+ return bitfield.mask_and_shift_to_bits(width, mask, 0)
@staticmethod
- def parse_bitfield(line):
+ def parse_bitfield(line, reg):
a = line.split(None, 1)
if len(a) != 2:
return None
(range_str, name) = a
- range = (None,None)
- if range_str.find(':') != -1:
- r = range_str.split(":")
- range = (int(r[0]),int(r[1]))
- else:
- range = (int(range_str),int(range_str))
+ bits = []
+ for s in range_str.split(','):
+ if ':' in s:
+ (start, end) = map( \
+ lambda s: reg.bit_number(int(s)),
+ s.split(':'))
+ bits.extend(range(start, end - 1, -1))
+ elif '<<' in s:
+ (mask, shift) = map(lambda s: int(s.strip()),
+ s.split('<<'))
+ bits.extend(bitfield.mask_and_shift_to_bits( \
+ reg.width, mask, shift))
+ elif s.startswith('&'):
+ mask = int(s[1:], 0)
+ bits.extend(bitfield.mask_to_bits(reg.width, \
+ mask))
+ else:
+ bits.append(reg.bit_number(int(s)))
+
+ return bitfield(bits, name)
+
- return bitfield(range[0], range[1], name)
@staticmethod
def parse_value(line):
return a
class register:
- def __init__(self, name, width):
- self.name = name
- self.width = width
+ bit_0_is_msb = 0
+ bit_0_is_lsb = 1
+
+ def __init__(self, id):
+ self.id = id
self.fields = []
+ # set defaults
+ self.name = None
+ self.bit_order = self.bit_0_is_msb
+ self.width = 64
- def add_field(self, field,):
+ def add_field(self, field):
self.fields.append(field)
- def decode(self, value):
- field_width = (self.width + 3) / 4
+ def decode(self, value, ignore_zero):
+ field_width = math.floor((self.width + 3) / 4)
name_width = max(map(lambda f: len(f.name), self.fields))
+
str = "0x%0*lx [%d]\n" % (field_width, value, value)
+
for field in self.fields:
- v = field.mask(self.width, value);
+ v = field.mask(self, value);
+ if ignore_zero and v == 0:
+ continue
desc = field.value(v)
if desc is not None:
- str += "%*s: 0x%s [%s]\n" \
+ str += "%*s: 0x%x [%s]\n" \
% (name_width, field.name, v, desc)
else:
str += "%*s: 0x%x\n" \
% (name_width, field.name, v)
return str
- def __str__(self):
- str = self.name + "\n"
- for f in self.fields:
- str += "\t%s\n" % f
- return str
+ def bit_number(self, number):
+ if self.bit_order == self.bit_0_is_lsb:
+ number = self.width - number - 1
+ return number
def list_regs(regs):
- for (id, r) in regs.iteritems():
- print "%18s : %s" % (id, r.name)
+ for (id, r) in regs.items():
+ print("%18s : %s" % (id, r.name))
def search_regs(regs, str):
return dict((k, regs[k]) for k in regs \
def parse_config(bnf, regs, file):
f = open(file)
- tokens = bnf.parseString("".join(f.readlines()))
+ tokens = bnf.parseString(f.read())
+
+ order_map = {'bit-0-is-lsb': register.bit_0_is_lsb,
+ 'bit-0-is-msb': register.bit_0_is_msb,
+ 'ibm': register.bit_0_is_msb,
+ 'default': register.bit_0_is_msb}
for tok in tokens:
ts = tok.asList()
id = ts.pop(0)
- if regs.has_key(id):
+ if id in regs:
raise ConfigurationError(file,
"Register %s is already defined" % id)
- # default to 64 bit registers
- width = 64
- name = None
+ reg = register(id)
+
+ alias_id = None
fields = []
for t in ts:
if t[0] == 'name':
name = t[1]
- name = name.strip()
+ reg.name = name.strip()
elif t[0] == 'width':
- width = int(t[1])
+ reg.width = int(t[1])
elif t[0] == 'field':
- f = bitfield.parse_bitfield(t[1])
+ f = bitfield.parse_bitfield(t[1], reg)
if f is None:
raise ConfigurationError(file,
"Invalid field in %s" % id)
"Invalid value in %s" % id)
fields[-1].add_value(v[0], v[1])
+ elif t[0] == 'order':
+ if len(fields) != 0:
+ raise ConfigurationError(file,
+ ("bit order defined after " \
+ + "fields in %s") % id)
+
+ order_str = t[1].strip().lower()
+ order_str = order_str.replace(' ', '-')
+
+ if order_str not in order_map.keys():
+ raise ConfigurationError(file,
+ "Invalid bit order %s in %s" % \
+ (order_str, id))
+ reg.bit_order = order_map[order_str]
+
+ elif t[0] == 'alias':
+ alias_id = t[1].strip()
+
+ if alias_id is not None:
+ if reg.name is not None or fields != []:
+ raise ConfigurationError(file, ("Definiton " \
+ + "for %s is an alias, but has other " \
+ + "attributes") % id)
+
+ if not regs.has_key(alias_id):
+ raise ConfigurationError(file, "Aliasing "
+ "non-existent register %s (from %s)" \
+ % (alias_id, id))
+
+ reg = regs[alias_id]
+ continue
- if name is None or name == '':
+ if reg.name is None or reg.name == '':
raise ConfigurationError(file,
"No name for entry %s" % id)
raise ConfigurationError(file,
"Register %s has no fields" % id)
- r = register(name, width)
for f in fields:
- r.add_field(f)
+ reg.add_field(f)
- regs[id] = r
+ regs[id] = reg
def parse_config_dir(data, dir, fnames):
(bnf, regs) = data
if not os.path.exists(conf):
continue
if os.path.isdir(conf):
- os.path.walk(conf, parse_config_dir, conf_data)
+ for c in os.walk(conf):
+ parse_config_dir(conf_data, c[0], c[2])
else:
parse_config(bnf, regs, conf)
return regs
def usage(prog):
- print "Usage: %s <-l> | <-s pattern> | register [value...]" % prog
+ print("Usage: %s <-l> | <-s pattern> | [-n] register [value...]" % prog)
+
+def decode_value(reg, value, options):
+ try:
+ i = int(value, 0)
+ except ValueError:
+ print("error: invalid value '%s'" % value)
+ return
+
+ if i > ((1 << reg.width) - 1):
+ print("error: value '%s' is too large " + \
+ "for %d-bit register '%s'") % (value, reg.width, reg.id)
+ return
+
+ print(reg.decode(i, options['non-zero']))
+
def main():
try:
- (opts, args) = getopt(sys.argv[1:], "hls:", \
- ["help", "list", "search="])
+ (opts, args) = getopt(sys.argv[1:], "hlns:", \
+ ["help", "list", "non-zero", "search="])
except GetoptError:
usage(sys.argv[0])
return 1
try:
regs = parse_all_configs(configs)
- except ConfigurationError, e:
- print "Error parsing configuration file %s:\n\t%s" % \
- (e.file, e.message)
+ except ConfigurationError as e:
+ print("Error parsing configuration file %s:\n\t%s" % \
+ (e.file, e.message))
return 1
if regs == {}:
- print "No configuration available"
+ print("No configuration available")
return 1
+ options = {}
+ options['non-zero'] = False
+
for o, a in opts:
if o in ("-h", "--help"):
usage(sys.argv[0])
list_regs(search_regs(regs, a))
return
+ if o in ("-n", "--non-zero"):
+ options['non-zero'] = True
if not args:
usage(sys.argv[0])
return 1
- a = args.pop(0)
- if not regs.has_key(a):
- print "No such register '%s'. Valid regs are:" % a
- list_regs(regs)
+ reg_id = args.pop(0)
+ if reg_id not in regs:
+ print("No such register '%s'" % reg_id)
return 1
- r = regs[a]
- print "decoding as %s" % r.name
+ reg = regs[reg_id]
+ print("decoding as %s" % reg.name)
if args:
- values = args
+ value_iter = args.__iter__()
else:
- try:
- values = sys.stdin.readlines()
- except KeyboardInterrupt, e:
- return
+ value_iter = iter(sys.stdin.readline, '')
- for value in values:
- i = long(value.strip(), 0)
- print r.decode(i)
+ try:
+ for value in value_iter:
+ decode_value(reg, value.strip(), options)
+ except KeyboardInterrupt:
+ pass
return 0