3 # Utility to decode register values
4 # Copyright (c) 2006 Jeremy Kerr <jk@ozlabs.org>
5 # Released under the GNU General Public License version 2 or later
7 # Documentation and updates at: http://ozlabs.org/~jk/code/bitfield
12 from pyparsing import Literal, Word, ZeroOrMore, Group, Dict, Optional, \
13 printables, ParseException, restOfLine
14 from getopt import getopt, GetoptError
16 # List of paths to look for configuration files. If a directory is specified,
17 # it will be (recursively) scanned for .conf files.
18 configs = [os.path.join(os.getenv("HOME"), ".bitfields.conf"),
19 os.path.join(os.getenv("HOME"), ".bitfields.d")]
22 def __init__(self, bits, name):
30 def add_value(self, value, description):
31 self.values[int(value)] = description
33 def mask(self, reg_width, value):
35 out_len = len(self.bits)
36 for out_bit in range(0, out_len):
37 in_bit = self.bits[out_bit]
38 # shift this bit down to the LSB (and mask the rest)
39 i = (value >> (reg_width - in_bit - 1)) & 1
40 # shift back to the output position in the field
41 i <<= out_len - out_bit - 1
45 def value(self, value):
46 if value in self.values:
47 return self.values[value]
51 def parse_bitfield(line):
52 a = line.split(None, 1)
58 for s in range_str.split(','):
60 (start, end) = s.split(':')
61 bits.extend(range(int(start), int(end) + 1, 1))
65 return bitfield(bits, name)
68 def parse_value(line):
69 a = line.split(None, 1)
75 def __init__(self, id, name, width):
81 def add_field(self, field):
82 self.fields.append(field)
84 def decode(self, value, ignore_zero):
85 field_width = (self.width + 3) / 4
86 name_width = max(map(lambda f: len(f.name), self.fields))
88 str = "0x%0*lx [%d]\n" % (field_width, value, value)
90 for field in self.fields:
91 v = field.mask(self.width, value);
92 if ignore_zero and v == 0:
96 str += "%*s: 0x%x [%s]\n" \
97 % (name_width, field.name, v, desc)
99 str += "%*s: 0x%x\n" \
100 % (name_width, field.name, v)
104 for (id, r) in regs.iteritems():
105 print "%18s : %s" % (id, r.name)
107 def search_regs(regs, str):
108 return dict((k, regs[k]) for k in regs \
109 if str.lower() in regs[k].name.lower() + k.lower())
111 class ConfigurationError(Exception):
112 def __init__(self, file, message):
114 self.message = message
116 def parse_config(bnf, regs, file):
119 tokens = bnf.parseString(f.read())
126 raise ConfigurationError(file,
127 "Register %s is already defined" % id)
129 # default to 64 bit registers
138 elif t[0] == 'width':
140 elif t[0] == 'field':
141 f = bitfield.parse_bitfield(t[1])
143 raise ConfigurationError(file,
144 "Invalid field in %s" % id)
146 elif t[0] == 'value':
148 raise ConfigurationError(file,
149 "No field for value in %s" % id)
150 v = bitfield.parse_value(t[1])
152 raise ConfigurationError(file,
153 "Invalid value in %s" % id)
155 fields[-1].add_value(v[0], v[1])
157 if name is None or name == '':
158 raise ConfigurationError(file,
159 "No name for entry %s" % id)
162 raise ConfigurationError(file,
163 "Register %s has no fields" % id)
165 r = register(id, name, width)
171 def parse_config_dir(data, dir, fnames):
174 full_fname = os.path.join(dir, fname)
176 if os.path.isdir(full_fname):
179 if fname.endswith('.conf'):
180 parse_config(bnf, regs, full_fname)
182 def parse_all_configs(configs):
185 # set up the bnf to be used for each file
186 lbrack = Literal("[").suppress()
187 rbrack = Literal("]").suppress()
188 colon = Literal(":").suppress()
191 comment = semi + Optional(restOfLine)
193 nonrbrack = "".join([c for c in printables if c != "]"]) + " \t"
194 noncolon = "".join([c for c in printables if c != ":"]) + " \t"
196 sectionDef = lbrack + Word(nonrbrack) + rbrack
197 keyDef = ~lbrack + Word(noncolon) + colon + restOfLine
199 bnf = Dict(ZeroOrMore(Group(sectionDef + ZeroOrMore(Group(keyDef)))))
202 # bundle into a single var that can be passed to os.path.walk
203 conf_data = (bnf, regs)
206 if not os.path.exists(conf):
208 if os.path.isdir(conf):
209 os.path.walk(conf, parse_config_dir, conf_data)
211 parse_config(bnf, regs, conf)
215 print "Usage: %s <-l> | <-s pattern> | [-n] register [value...]" % prog
217 def decode_value(reg, value, options):
220 except ValueError, e:
221 print "error: invalid value '%s'" % value
224 if i > ((1 << reg.width) - 1):
225 print ("error: value '%s' is too large " + \
226 "for %d-bit register '%s'") % (value, reg.width, reg.id)
229 print reg.decode(i, options.has_key('non_zero'))
234 (opts, args) = getopt(sys.argv[1:], "hlns:", \
235 ["help", "list", "non-zero", "search="])
241 regs = parse_all_configs(configs)
242 except ConfigurationError, e:
243 print "Error parsing configuration file %s:\n\t%s" % \
248 print "No configuration available"
252 options['non-zero'] = False
255 if o in ("-h", "--help"):
259 if o in ("-l", "--list"):
263 if o in ("-s", "--search"):
264 list_regs(search_regs(regs, a))
267 if o in ("-n", "--non-zero"):
268 options['non-zero'] = True
275 if not regs.has_key(reg_id):
276 print "No such register '%s'" % reg_id
280 print "decoding as %s" % reg.name
283 value_iter = args.__iter__()
285 value_iter = iter(sys.stdin.readline, '')
288 for value in value_iter:
289 decode_value(reg, value.strip(), options)
290 except KeyboardInterrupt, e:
295 if __name__ == "__main__":