Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: src/trusted/validator_arm/dgen_core.py

Issue 10191011: Moving dgen_ scripts out of validator_arm into a common directory. (Closed)
Patch Set: Updates per code review. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/trusted/validator_arm/build.scons ('k') | src/trusted/validator_arm/dgen_decoder_output.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6 #
7
8 """
9 The core object model for the Decoder Generator. The dg_input and dg_output
10 modules both operate in terms of these classes.
11 """
12
13 def _popcount(int):
14 """Returns the number of 1 bits in the input."""
15 count = 0
16 for bit in range(0, 32):
17 count = count + ((int >> bit) & 1)
18 return count
19
20
21 class BitPattern(object):
22 """A pattern for matching strings of bits. See parse() for syntax."""
23
24 @staticmethod
25 def parse(pattern, hi_bit, lo_bit):
26 """ Parses a string pattern describing some bits. The string can
27 consist of '1' and '0' to match bits explicitly, 'x' or 'X' to ignore
28 bits, '_' as an ignored separator, and an optional leading '~' to
29 negate the entire pattern. Examples:
30 10xx0
31 1111_xxxx
32 ~111x
33
34 The pattern may also optionally be '-', which is equivalent to a
35 sequence of 'xxx...xxx' of the requested width.
36
37 Args:
38 pattern: a string in the format described above.
39 hi_bit: the top of the range matched by this pattern, inclusive.
40 lo_bit: the bottom of the range matched by this pattern, inclusive.
41 Returns:
42 A BitPattern instance that describes the match, and is capable of
43 transforming itself to a C expression.
44 Raises:
45 Exception: the input didn't meet the rules described above.
46 """
47 num_bits = hi_bit - lo_bit + 1
48 # Convert - into a full-width don't-care pattern.
49 if pattern == '-':
50 return BitPattern.parse('x' * num_bits, hi_bit, lo_bit)
51
52 # Derive the operation type from the presence of a leading tilde.
53 if pattern.startswith('~'):
54 op = '!='
55 pattern = pattern[1:]
56 else:
57 op = '=='
58
59 # Allow use of underscores anywhere in the pattern, as a separator.
60 pattern = pattern.replace('_', '')
61
62 if len(pattern) != num_bits:
63 raise Exception('Pattern %s is wrong length for %d:%u'
64 % (pattern, hi_bit, lo_bit))
65
66 mask = 0
67 value = 0
68 for c in pattern:
69 if c == '1':
70 mask = (mask << 1) | 1
71 value = (value << 1) | 1
72 elif c == '0':
73 mask = (mask << 1) | 1
74 value = value << 1
75 elif c == 'x' or c == 'X':
76 mask = mask << 1
77 value = value << 1
78 else:
79 raise Exception('Invalid characters in pattern %s' % pattern)
80
81 mask = mask << lo_bit
82 value = value << lo_bit
83 return BitPattern(mask, value, op)
84
85 @staticmethod
86 def parse_catch(pattern, hi_bit, lo_bit):
87 """"Calls parse with given arguments, and catches exceptions
88 raised. Prints raised exceptions and returns None.
89 """
90 try:
91 return BitPattern.parse(pattern, hi_bit, lo_bit);
92 except Exception as ex:
93 print "Error: %s" % ex
94 return None
95
96 def __init__(self, mask, value, op):
97 """Initializes a BitPattern.
98
99 Args:
100 mask: an integer with 1s in the bit positions we care about (e.g.
101 those that are not X)
102 value: an integer that would match our pattern, subject to the mask.
103 op: either '==' or '!=', if the pattern is positive or negative,
104 respectively.
105 """
106 self.mask = mask
107 self.value = value
108 self.op = op
109 self.significant_bits = _popcount(mask)
110
111 def conflicts(self, other):
112 """Returns an integer with a 1 in each bit position that conflicts
113 between the two patterns, and 0s elsewhere. Note that this is only
114 useful if the masks and ops match.
115 """
116 return (self.mask & self.value) ^ (other.mask & other.value)
117
118 def is_complement(self, other):
119 """Checks if two patterns are complements of each other. This means
120 they have the same mask and pattern bits, but one is negative.
121 """
122 return (self.op != other.op
123 and self.mask == other.mask
124 and self.value == other.value)
125
126 def is_strictly_compatible(self, other):
127 """Checks if two patterns are safe to merge using +, but are not ==."""
128 if self.is_complement(other):
129 return True
130 elif self.op == other.op:
131 return (self.mask == other.mask
132 and _popcount(self.conflicts(other)) == 1)
133 return False
134
135 def __add__(self, other):
136 """Merges two compatible patterns into a single pattern that matches
137 everything either pattern would have matched.
138 """
139 assert (self == other) or self.is_strictly_compatible(other)
140
141 if self.op == other.op:
142 c = self.conflicts(other)
143 return BitPattern((self.mask | other.mask) ^ c,
144 (self.value | other.value) ^ c, self.op)
145 else:
146 return BitPattern(0, 0, '==') # matches anything
147
148 def to_c_expr(self, input):
149 """Converts this pattern to a C expression.
150 Args:
151 input: the name (string) of the C variable to be tested by the
152 expression.
153 Returns:
154 A string containing a C expression.
155 """
156 if self.mask == 0:
157 return 'true'
158 else:
159 return ('(%s & 0x%08X) %s 0x%08X'
160 % (input, self.mask, self.op, self.value))
161
162 def __cmp__(self, other):
163 """Compares two patterns for sorting purposes. We sort by
164 - # of significant bits, DESCENDING,
165 - then mask value, numerically,
166 - then value, numerically,
167 - and finally op.
168
169 This is also used for equality comparison using ==.
170 """
171 return (cmp(other.significant_bits, self.significant_bits)
172 or cmp(self.mask, other.mask)
173 or cmp(self.value, other.value)
174 or cmp(self.op, other.op))
175
176 def __repr__(self):
177 pat = []
178 for i in range(0, 32):
179 if (self.mask >> i) & 1:
180 pat.append(`(self.value >> i) & 1`)
181 else:
182 pat.append('x')
183 if self.op == '!=':
184 pat.append('~')
185 return ''.join(reversed(pat))
186
187
188 class Table(object):
189 """A table in the instruction set definition. Each table contains 1+
190 columns, and 1+ rows. Each row contains a bit pattern for each column, plus
191 the action to be taken if the row matches."""
192
193 def __init__(self, name, citation):
194 """Initializes a new Table.
195 Args:
196 name: a name for the table, used to reference it from other tables.
197 citation: the section in the ISA spec this table was derived from.
198 """
199 self.name = name
200 self.citation = citation
201 self.rows = []
202 self._columns = []
203
204 def add_column(self, name, hi_bit, lo_bit):
205 """Adds a column to the table.
206
207 Because we don't use the column information for very much, we don't give
208 it a type -- we store it as a list of tuples.
209
210 Args:
211 name: the name of the column (for diagnostic purposes only).
212 hi_bit: the leftmost bit included.
213 lo_bit: the rightmost bit included.
214 """
215 self._columns.append( (name, hi_bit, lo_bit) )
216
217 def add_row(self, patterns, action, arch):
218 """Adds a row to the table.
219 Args:
220 patterns: a list containing a BitPattern for every column in the
221 table.
222 action: The action associated with the row. Must either be
223 a DecoderAction or a DecoderMethod.
224 arch: a string defining the architectures it applies to. None
225 implies all.
226 """
227 self.rows.append(Row(patterns, action, arch))
228
229 def define_pattern(self, pattern, column):
230 """Converts the given input pattern (for the given column) to the
231 internal form. Returns None if pattern is bad.
232 """
233 if column >= len(self._columns): return None
234 col = self._columns[column]
235 return BitPattern.parse_catch(pattern, col[1], col[2])
236
237 def action_filter(self, names):
238 """Returns a table with DecoderActions reduced to the given field names.
239 Used to optimize out duplicates, depending on context.
240 """
241 table = Table(self.name, self.citation)
242 table._columns = self._columns
243 for r in self.rows:
244 table.add_row(r.patterns, r.action.action_filter(names), r.arch)
245 return table
246
247 class DecoderAction:
248 """An action defining a class decoder to apply.
249
250 Corresponds to the parsed decoder action:
251 decoder_action ::= id (id (word (id)?)?)?
252
253 Fields are:
254 name - Name of class decoder selected.
255 rule - Name of the rule in ARM manual that defines
256 the decoder action.
257 pattern - The placement of 0/1's within any instruction
258 that is matched by the corresponding rule.
259 constraints - Additional constraints that apply to the rule.
260 """
261 def __init__(self, name, rule, pattern, constraints):
262 self.name = name
263 self.rule = rule
264 self.pattern = pattern
265 self.constraints = constraints
266
267 def action_filter(self, names):
268 return DecoderAction(
269 self.name if 'name' in names else None,
270 self.rule if 'rule' in names else None,
271 self.pattern if 'pattern' in names else None,
272 self.constraints if 'constraints' in names else None)
273
274 def __eq__(self, other):
275 return (other.__class__.__name__ == 'DecoderAction'
276 and self.name == other.name
277 and self.rule == other.rule
278 and self.pattern == other.pattern
279 and self.constraints == other.constraints)
280
281 def __cmp__(self, other):
282 # Order lexicographically on type/fields.
283 value = cmp(other.__class__.__name__, 'DecoderAction')
284 if value != 0: return value
285 value = cmp(self.name, other.name)
286 if value != 0: return value
287 value = cmp(self.rule, other.rule)
288 if value != 0: return value
289 value = cmp(self.pattern, other.pattern)
290 if value != 0: return value
291 return cmp(self.constraints, other.constraints)
292
293 def __hash__(self):
294 return (hash('DecoderAction') + hash(self.name) + hash(self.rule) +
295 hash(self.pattern) + hash(self.constraints))
296
297 def __repr__(self):
298 return '=%s %s %s %s' % (self.name, self.rule,
299 self.pattern, self.constraints)
300
301 class DecoderMethod(object):
302 """An action defining a parse method to call.
303
304 Corresponds to the parsed decoder method:
305 decoder_method ::= '->' id
306
307 Fields are:
308 name - The name of the corresponding table (i.e. method) that
309 should be used to continue searching for a matching class
310 decoder.
311 """
312 def __init__(self, name):
313 self.name = name
314
315 def action_filter(self, unused_names):
316 return self
317
318 def __eq__(self, other):
319 return (self.__class__.__name__ == 'DecoderMethod'
320 and self.name == other.name)
321
322 def __cmp__(self, other):
323 # Lexicographically compare types/fields.
324 value = cmp(other.__class__.__name__, 'DecoderMethod')
325 if value != 0: return value
326 return cmp(self.name, other.name)
327
328 def __hash__(self):
329 return hash('DecoderMethod') + hash(self.name)
330
331 def __repr__(self):
332 return '->%s' % self.name
333
334 class Row(object):
335 """ A row in a Table."""
336 def __init__(self, patterns, action, arch):
337 """Initializes a Row.
338 Args:
339 patterns: a list of BitPatterns that must match for this Row to
340 match.
341 action: the action to be taken if this Row matches.
342 arch: the minimum architecture that this Row can match.
343 """
344 self.patterns = patterns
345 self.action = action
346 self.arch = arch
347
348 self.significant_bits = 0
349 for p in patterns:
350 self.significant_bits += p.significant_bits
351
352 def can_merge(self, other):
353 """Determines if we can merge two Rows."""
354 if self.action != other.action or self.arch != other.arch:
355 return False
356
357 equal_columns = 0
358 compat_columns = 0
359 for (a, b) in zip(self.patterns, other.patterns):
360 if a == b:
361 equal_columns += 1
362 if a.is_strictly_compatible(b):
363 compat_columns += 1
364
365 cols = len(self.patterns)
366 return (equal_columns == cols
367 or (equal_columns == cols - 1 and compat_columns == 1))
368
369 def __add__(self, other):
370 assert self.can_merge(other) # Caller is expected to check!
371 return Row([a + b for (a, b) in zip(self.patterns, other.patterns)],
372 self.action, self.arch)
373
374 def __cmp__(self, other):
375 """Compares two rows, so we can order pattern matches by specificity.
376 """
377 return (cmp(self.patterns, other.patterns)
378 or cmp(self.action, other.action))
379
380 def __repr__(self):
381 return 'Row(%s, %s)' % (repr(self.patterns), repr(self.action))
382
383 class Decoder(object):
384 """Defines a class decoder which consists of set of tables.
385
386 A decoder has a primary (i.e. start) table to parse intructions (and
387 select the proper ClassDecoder), as well as a set of additional
388 tables to complete the selection of a class decoder. Instances of
389 this class correspond to the internal representation of parsed
390 decoder tables recognized by dgen_input.py (see that file for
391 details).
392
393 Fields are:
394 primary - The entry parse table to find a class decoder.
395 tables - The (sorted) set of tables defined by a decoder.
396
397 Note: maintains restriction that tables have unique names.
398 """
399
400 def __init__(self):
401 self.primary = None
402 self._is_sorted = False
403 self._tables = []
404
405 def add(self, table):
406 """Adds the table to the set of tables. Returns true if successful.
407 """
408 if filter(lambda(t): t.name == table.name, self._tables):
409 # Table with name already defined, report error.
410 return False
411 else:
412 if not self._tables:
413 self.primary = table
414 self._tables.append(table)
415 self.is_sorted = False
416 return True
417
418 def tables(self):
419 """Returns the sorted (by table name) list of tables"""
420 if self._is_sorted: return self._tables
421 self._tables = sorted(self._tables, key=lambda(tbl): tbl.name)
422 self._is_sorted = True
423 return self._tables
424
425 def action_filter(self, names):
426 """Returns a new set of tables with actions reduced to the set of
427 field names.
428 """
429 decoder = Decoder()
430 decoder._tables = sorted([ t.action_filter(names) for t in self._tables ],
431 key=lambda(tbl): tbl.name)
432 decoder.primary = filter(
433 lambda(t): t.name == self.primary.name, self._tables)[0]
434 return decoder
435
436 def decoders(self):
437 """Returns the sorted sequence of DecoderAction's defined in the tables."""
438 decoders = set()
439 for t in self._tables:
440 for r in t.rows:
441 if r.action.__class__.__name__ == 'DecoderAction':
442 decoders.add(r.action)
443 return sorted(decoders)
444
445 def rules(self):
446 """Returns the sorted sequence of DecoderActions that define
447 the rule field.
448 """
449 return sorted(filter(lambda (r): r.rule, self.decoders()))
OLDNEW
« no previous file with comments | « src/trusted/validator_arm/build.scons ('k') | src/trusted/validator_arm/dgen_decoder_output.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698