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, start_bit, end_bit, name):
23 self.start_bit = start_bit
24 self.end_bit = end_bit
35 return 1 + self.end_bit - self.start_bit
37 def add_value(self, value, description):
38 self.values[int(value)] = description
40 def mask(self, reg_width, value):
41 shift = (reg_width - 1) - self.end_bit
42 return (((2 ** self.width() - 1) << (shift))
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 if range_str.find(':') != -1:
59 r = range_str.split(":")
60 range = (int(r[0]),int(r[1]))
62 range = (int(range_str),int(range_str))
64 return bitfield(range[0], range[1], name)
67 def parse_value(line):
68 a = line.split(None, 1)
74 def __init__(self, name, width):
79 def add_field(self, field,):
80 self.fields.append(field)
82 def decode(self, value, ignore_zero):
83 field_width = (self.width + 3) / 4
84 name_width = max(map(lambda f: len(f.name), self.fields))
85 str = "0x%0*lx [%d]\n" % (field_width, value, value)
86 for field in self.fields:
87 v = field.mask(self.width, value);
88 if ignore_zero and v == 0:
92 str += "%*s: 0x%s [%s]\n" \
93 % (name_width, field.name, v, desc)
95 str += "%*s: 0x%x\n" \
96 % (name_width, field.name, v)
100 for (id, r) in regs.iteritems():
101 print "%18s : %s" % (id, r.name)
103 def search_regs(regs, str):
104 return dict((k, regs[k]) for k in regs \
105 if str.lower() in regs[k].name.lower() + k.lower())
107 class ConfigurationError(Exception):
108 def __init__(self, file, message):
110 self.message = message
112 def parse_config(bnf, regs, file):
115 tokens = bnf.parseString("".join(f.readlines()))
122 raise ConfigurationError(file,
123 "Register %s is already defined" % id)
125 # default to 64 bit registers
134 elif t[0] == 'width':
136 elif t[0] == 'field':
137 f = bitfield.parse_bitfield(t[1])
139 raise ConfigurationError(file,
140 "Invalid field in %s" % id)
142 elif t[0] == 'value':
144 raise ConfigurationError(file,
145 "No field for value in %s" % id)
146 v = bitfield.parse_value(t[1])
148 raise ConfigurationError(file,
149 "Invalid value in %s" % id)
151 fields[-1].add_value(v[0], v[1])
153 if name is None or name == '':
154 raise ConfigurationError(file,
155 "No name for entry %s" % id)
158 raise ConfigurationError(file,
159 "Register %s has no fields" % id)
161 r = register(name, width)
167 def parse_config_dir(data, dir, fnames):
170 full_fname = os.path.join(dir, fname)
172 if os.path.isdir(full_fname):
175 if fname.endswith('.conf'):
176 parse_config(bnf, regs, full_fname)
178 def parse_all_configs(configs):
181 # set up the bnf to be used for each file
182 lbrack = Literal("[").suppress()
183 rbrack = Literal("]").suppress()
184 colon = Literal(":").suppress()
187 comment = semi + Optional(restOfLine)
189 nonrbrack = "".join([c for c in printables if c != "]"]) + " \t"
190 noncolon = "".join([c for c in printables if c != ":"]) + " \t"
192 sectionDef = lbrack + Word(nonrbrack) + rbrack
193 keyDef = ~lbrack + Word(noncolon) + colon + restOfLine
195 bnf = Dict(ZeroOrMore(Group(sectionDef + ZeroOrMore(Group(keyDef)))))
198 # bundle into a single var that can be passed to os.path.walk
199 conf_data = (bnf, regs)
202 if not os.path.exists(conf):
204 if os.path.isdir(conf):
205 os.path.walk(conf, parse_config_dir, conf_data)
207 parse_config(bnf, regs, conf)
211 print "Usage: %s <-l> | <-s pattern> | register [value...]" % prog
215 (opts, args) = getopt(sys.argv[1:], "hlns:", \
216 ["help", "list", "non-zero", "search="])
222 regs = parse_all_configs(configs)
223 except ConfigurationError, e:
224 print "Error parsing configuration file %s:\n\t%s" % \
229 print "No configuration available"
233 options['non-zero'] = False
236 if o in ("-h", "--help"):
240 if o in ("-l", "--list"):
244 if o in ("-s", "--search"):
245 list_regs(search_regs(regs, a))
248 if o in ("-n", "--non-zero"):
249 options['non-zero'] = True
256 if not regs.has_key(reg_id):
257 print "No such register '%s'" % reg_id
261 print "decoding as %s" % r.name
267 values = sys.stdin.readlines()
268 except KeyboardInterrupt, e:
272 i = long(value.strip(), 0)
273 print r.decode(i, options['non-zero'])
277 if __name__ == "__main__":