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 = ["/etc/bitfield.d", "/etc/bitfield",
19 os.path.join(os.getenv("HOME"), ".bitfield.d"),
20 os.path.join(os.getenv("HOME"), ".bitfield.conf")]
23 def __init__(self, bits, name):
31 def add_value(self, value, description):
32 self.values[int(value, 0)] = description
34 def mask(self, reg, value):
36 out_len = len(self.bits)
38 if reg.bit_order == reg.bit_0_is_msb:
39 bit_pairs = zip(self.bits, range(0, out_len))
41 bit_pairs = zip(self.bits, range(out_len - 1, -1, -1))
43 for (in_bit, out_bit) in bit_pairs:
44 # shift this bit down to the LSB (and mask the rest)
45 i = (value >> (reg.width - in_bit - 1)) & 1
46 # shift back to the output position in the field
47 i <<= out_len - out_bit - 1
51 def value(self, value):
52 if value in self.values:
53 return self.values[value]
57 def mask_and_shift_to_bits(width, mask, shift):
60 for i in range(0, width):
62 bits.insert(0, width - i - 1 - shift)
66 def mask_to_bits(width, mask):
67 return bitfield.mask_and_shift_to_bits(width, mask, 0)
70 def parse_bitfield(line, reg):
71 a = line.split(None, 1)
77 for s in range_str.split(','):
80 lambda s: reg.bit_number(int(s)),
82 bits.extend(range(start, end - 1, -1))
84 (mask, shift) = map(lambda s: int(s.strip()),
86 bits.extend(bitfield.mask_and_shift_to_bits( \
87 reg.width, mask, shift))
88 elif s.startswith('&'):
90 bits.extend(bitfield.mask_to_bits(reg.width, \
93 bits.append(reg.bit_number(int(s)))
95 return bitfield(bits, name)
100 def parse_value(line):
101 a = line.split(None, 1)
110 def __init__(self, id):
115 self.bit_order = self.bit_0_is_msb
118 def add_field(self, field):
119 self.fields.append(field)
121 def decode(self, value, ignore_zero):
122 field_width = (self.width + 3) / 4
123 name_width = max(map(lambda f: len(f.name), self.fields))
125 str = "0x%0*lx [%d]\n" % (field_width, value, value)
127 for field in self.fields:
128 v = field.mask(self, value);
129 if ignore_zero and v == 0:
131 desc = field.value(v)
133 str += "%*s: 0x%x [%s]\n" \
134 % (name_width, field.name, v, desc)
136 str += "%*s: 0x%x\n" \
137 % (name_width, field.name, v)
140 def bit_number(self, number):
141 if self.bit_order == self.bit_0_is_lsb:
142 number = self.width - number - 1
146 for (id, r) in regs.iteritems():
147 print "%18s : %s" % (id, r.name)
149 def search_regs(regs, str):
150 return dict((k, regs[k]) for k in regs \
151 if str.lower() in regs[k].name.lower() + k.lower())
153 class ConfigurationError(Exception):
154 def __init__(self, file, message):
156 self.message = message
158 def parse_config(bnf, regs, file):
161 tokens = bnf.parseString(f.read())
163 order_map = {'bit-0-is-lsb': register.bit_0_is_lsb,
164 'bit-0-is-msb': register.bit_0_is_msb,
165 'ibm': register.bit_0_is_msb,
166 'default': register.bit_0_is_msb}
173 raise ConfigurationError(file,
174 "Register %s is already defined" % id)
184 reg.name = name.strip()
185 elif t[0] == 'width':
186 reg.width = int(t[1])
187 elif t[0] == 'field':
188 f = bitfield.parse_bitfield(t[1], reg)
190 raise ConfigurationError(file,
191 "Invalid field in %s" % id)
193 elif t[0] == 'value':
195 raise ConfigurationError(file,
196 "No field for value in %s" % id)
197 v = bitfield.parse_value(t[1])
199 raise ConfigurationError(file,
200 "Invalid value in %s" % id)
202 fields[-1].add_value(v[0], v[1])
203 elif t[0] == 'order':
205 raise ConfigurationError(file,
206 ("bit order defined after " \
207 + "fields in %s") % id)
209 order_str = t[1].strip().lower()
210 order_str = order_str.replace(' ', '-')
212 if order_str not in order_map.keys():
213 raise ConfigurationError(file,
214 "Invalid bit order %s in %s" % \
216 reg.bit_order = order_map[order_str]
218 elif t[0] == 'alias':
219 alias_id = t[1].strip()
221 if alias_id is not None:
222 if reg.name is not None or fields != []:
223 raise ConfigurationError(file, ("Definiton " \
224 + "for %s is an alias, but has other " \
225 + "attributes") % id)
227 if not regs.has_key(alias_id):
228 raise ConfigurationError(file, "Aliasing "
229 "non-existent register %s (from %s)" \
235 if reg.name is None or reg.name == '':
236 raise ConfigurationError(file,
237 "No name for entry %s" % id)
240 raise ConfigurationError(file,
241 "Register %s has no fields" % id)
248 def parse_config_dir(data, dir, fnames):
251 full_fname = os.path.join(dir, fname)
253 if os.path.isdir(full_fname):
256 if fname.endswith('.conf'):
257 parse_config(bnf, regs, full_fname)
259 def parse_all_configs(configs):
262 # set up the bnf to be used for each file
263 lbrack = Literal("[").suppress()
264 rbrack = Literal("]").suppress()
265 colon = Literal(":").suppress()
268 comment = semi + Optional(restOfLine)
270 nonrbrack = "".join([c for c in printables if c != "]"]) + " \t"
271 noncolon = "".join([c for c in printables if c != ":"]) + " \t"
273 sectionDef = lbrack + Word(nonrbrack) + rbrack
274 keyDef = ~lbrack + Word(noncolon) + colon + restOfLine
276 bnf = Dict(ZeroOrMore(Group(sectionDef + ZeroOrMore(Group(keyDef)))))
279 # bundle into a single var that can be passed to os.path.walk
280 conf_data = (bnf, regs)
283 if not os.path.exists(conf):
285 if os.path.isdir(conf):
286 os.path.walk(conf, parse_config_dir, conf_data)
288 parse_config(bnf, regs, conf)
292 print "Usage: %s <-l> | <-s pattern> | [-n] register [value...]" % prog
294 def decode_value(reg, value, options):
297 except ValueError, e:
298 print "error: invalid value '%s'" % value
301 if i > ((1 << reg.width) - 1):
302 print ("error: value '%s' is too large " + \
303 "for %d-bit register '%s'") % (value, reg.width, reg.id)
306 print reg.decode(i, options['non-zero'])
311 (opts, args) = getopt(sys.argv[1:], "hlns:", \
312 ["help", "list", "non-zero", "search="])
318 regs = parse_all_configs(configs)
319 except ConfigurationError, e:
320 print "Error parsing configuration file %s:\n\t%s" % \
325 print "No configuration available"
329 options['non-zero'] = False
332 if o in ("-h", "--help"):
336 if o in ("-l", "--list"):
340 if o in ("-s", "--search"):
341 list_regs(search_regs(regs, a))
344 if o in ("-n", "--non-zero"):
345 options['non-zero'] = True
352 if not regs.has_key(reg_id):
353 print "No such register '%s'" % reg_id
357 print "decoding as %s" % reg.name
360 value_iter = args.__iter__()
362 value_iter = iter(sys.stdin.readline, '')
365 for value in value_iter:
366 decode_value(reg, value.strip(), options)
367 except KeyboardInterrupt, e:
372 if __name__ == "__main__":