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
13 from pyparsing import Literal, Word, ZeroOrMore, Group, Dict, Optional, \
14 printables, ParseException, restOfLine
15 from getopt import getopt, GetoptError
17 # List of paths to look for configuration files. If a directory is specified,
18 # it will be (recursively) scanned for .conf files.
19 configs = ["/etc/bitfield.d", "/etc/bitfield",
20 os.path.join(os.getenv("HOME"), ".bitfield.d"),
21 os.path.join(os.getenv("HOME"), ".bitfield.conf")]
24 def __init__(self, bits, name):
32 def add_value(self, value, description):
33 self.values[int(value, 0)] = description
35 def mask(self, reg, value):
37 out_len = len(self.bits)
39 if reg.bit_order == reg.bit_0_is_msb:
40 bit_pairs = zip(self.bits, range(0, out_len))
42 bit_pairs = zip(self.bits, range(out_len - 1, -1, -1))
44 for (in_bit, out_bit) in bit_pairs:
45 # shift this bit down to the LSB (and mask the rest)
46 i = (value >> (reg.width - in_bit - 1)) & 1
47 # shift back to the output position in the field
48 i <<= out_len - out_bit - 1
52 def value(self, value):
53 if value in self.values:
54 return self.values[value]
58 def mask_and_shift_to_bits(width, mask, shift):
61 for i in range(0, width):
63 bits.insert(0, width - i - 1 - shift)
67 def mask_to_bits(width, mask):
68 return bitfield.mask_and_shift_to_bits(width, mask, 0)
71 def parse_bitfield(line, reg):
72 a = line.split(None, 1)
78 for s in range_str.split(','):
81 lambda s: reg.bit_number(int(s)),
83 bits.extend(range(start, end - 1, -1))
85 (mask, shift) = map(lambda s: int(s.strip()),
87 bits.extend(bitfield.mask_and_shift_to_bits( \
88 reg.width, mask, shift))
89 elif s.startswith('&'):
91 bits.extend(bitfield.mask_to_bits(reg.width, \
94 bits.append(reg.bit_number(int(s)))
96 return bitfield(bits, name)
101 def parse_value(line):
102 a = line.split(None, 1)
111 def __init__(self, id):
116 self.bit_order = self.bit_0_is_msb
119 def add_field(self, field):
120 self.fields.append(field)
122 def decode(self, value, ignore_zero):
123 field_width = math.floor((self.width + 3) / 4)
124 name_width = max(map(lambda f: len(f.name), self.fields))
126 str = "0x%0*lx [%d]\n" % (field_width, value, value)
128 for field in self.fields:
129 v = field.mask(self, value);
130 if ignore_zero and v == 0:
132 desc = field.value(v)
134 str += "%*s: 0x%x [%s]\n" \
135 % (name_width, field.name, v, desc)
137 str += "%*s: 0x%x\n" \
138 % (name_width, field.name, v)
141 def bit_number(self, number):
142 if self.bit_order == self.bit_0_is_lsb:
143 number = self.width - number - 1
147 for (id, r) in regs.items():
148 print("%18s : %s" % (id, r.name))
150 def search_regs(regs, str):
151 return dict((k, regs[k]) for k in regs \
152 if str.lower() in regs[k].name.lower() + k.lower())
154 class ConfigurationError(Exception):
155 def __init__(self, file, message):
157 self.message = message
159 def parse_config(bnf, regs, file):
162 tokens = bnf.parseString(f.read())
164 order_map = {'bit-0-is-lsb': register.bit_0_is_lsb,
165 'bit-0-is-msb': register.bit_0_is_msb,
166 'ibm': register.bit_0_is_msb,
167 'default': register.bit_0_is_msb}
174 raise ConfigurationError(file,
175 "Register %s is already defined" % id)
185 reg.name = name.strip()
186 elif t[0] == 'width':
187 reg.width = int(t[1])
188 elif t[0] == 'field':
189 f = bitfield.parse_bitfield(t[1], reg)
191 raise ConfigurationError(file,
192 "Invalid field in %s" % id)
194 elif t[0] == 'value':
196 raise ConfigurationError(file,
197 "No field for value in %s" % id)
198 v = bitfield.parse_value(t[1])
200 raise ConfigurationError(file,
201 "Invalid value in %s" % id)
203 fields[-1].add_value(v[0], v[1])
204 elif t[0] == 'order':
206 raise ConfigurationError(file,
207 ("bit order defined after " \
208 + "fields in %s") % id)
210 order_str = t[1].strip().lower()
211 order_str = order_str.replace(' ', '-')
213 if order_str not in order_map.keys():
214 raise ConfigurationError(file,
215 "Invalid bit order %s in %s" % \
217 reg.bit_order = order_map[order_str]
219 elif t[0] == 'alias':
220 alias_id = t[1].strip()
222 if alias_id is not None:
223 if reg.name is not None or fields != []:
224 raise ConfigurationError(file, ("Definiton " \
225 + "for %s is an alias, but has other " \
226 + "attributes") % id)
228 if not regs.has_key(alias_id):
229 raise ConfigurationError(file, "Aliasing "
230 "non-existent register %s (from %s)" \
236 if reg.name is None or reg.name == '':
237 raise ConfigurationError(file,
238 "No name for entry %s" % id)
241 raise ConfigurationError(file,
242 "Register %s has no fields" % id)
249 def parse_config_dir(data, dir, fnames):
252 full_fname = os.path.join(dir, fname)
254 if os.path.isdir(full_fname):
257 if fname.endswith('.conf'):
258 parse_config(bnf, regs, full_fname)
260 def parse_all_configs(configs):
263 # set up the bnf to be used for each file
264 lbrack = Literal("[").suppress()
265 rbrack = Literal("]").suppress()
266 colon = Literal(":").suppress()
269 comment = semi + Optional(restOfLine)
271 nonrbrack = "".join([c for c in printables if c != "]"]) + " \t"
272 noncolon = "".join([c for c in printables if c != ":"]) + " \t"
274 sectionDef = lbrack + Word(nonrbrack) + rbrack
275 keyDef = ~lbrack + Word(noncolon) + colon + restOfLine
277 bnf = Dict(ZeroOrMore(Group(sectionDef + ZeroOrMore(Group(keyDef)))))
280 # bundle into a single var that can be passed to os.path.walk
281 conf_data = (bnf, regs)
284 if not os.path.exists(conf):
286 if os.path.isdir(conf):
287 for c in os.walk(conf):
288 parse_config_dir(conf_data, c[0], c[2])
290 parse_config(bnf, regs, conf)
294 print("Usage: %s <-l> | <-s pattern> | [-n] register [value...]" % prog)
296 def decode_value(reg, value, options):
300 print("error: invalid value '%s'" % value)
303 if i > ((1 << reg.width) - 1):
304 print("error: value '%s' is too large " + \
305 "for %d-bit register '%s'") % (value, reg.width, reg.id)
308 print(reg.decode(i, options['non-zero']))
313 (opts, args) = getopt(sys.argv[1:], "hlns:", \
314 ["help", "list", "non-zero", "search="])
320 regs = parse_all_configs(configs)
321 except ConfigurationError as e:
322 print("Error parsing configuration file %s:\n\t%s" % \
327 print("No configuration available")
331 options['non-zero'] = False
334 if o in ("-h", "--help"):
338 if o in ("-l", "--list"):
342 if o in ("-s", "--search"):
343 list_regs(search_regs(regs, a))
346 if o in ("-n", "--non-zero"):
347 options['non-zero'] = True
354 if reg_id not in regs:
355 print("No such register '%s'" % reg_id)
359 print("decoding as %s" % reg.name)
362 value_iter = args.__iter__()
364 value_iter = iter(sys.stdin.readline, '')
367 for value in value_iter:
368 decode_value(reg, value.strip(), options)
369 except KeyboardInterrupt:
374 if __name__ == "__main__":