@@ -191,44 +191,44 @@ def __exit__(self, *execinfo):
191191
192192
193193def match_bitpattern (w : WireVector , bitpattern : str ,
194- field_map : dict = None ) -> MatchedFields :
195- """Returns a single-bit WireVector that is 1 if and only if ``w`` matches
194+ field_map : dict [ str , str ] = None ) -> MatchedFields :
195+ """Returns a single-bit `` WireVector`` that is 1 if and only if ``w`` matches
196196 the ``bitpattern``, and a tuple containing the matched fields, if any.
197197 Compatible with the ``with`` statement.
198198
199- :param WireVector w: The WireVector to be compared to the bitpattern
199+ :param w: The `` WireVector`` to be compared to the `` bitpattern``
200200 :param bitpattern: A string holding the pattern (of bits and wildcards) to
201201 match
202202 :param field_map: (optional) A map from single-character field name in the
203- bitpattern to the desired name of field in the returned namedtuple. If
204- given, all non-"1"/"0"/"?" characters in the `bitpattern` must be
203+ bitpattern to the desired name of field in the returned `` namedtuple`` . If
204+ given, all non-``1``/``0``/``?`` characters in the `` bitpattern` ` must be
205205 present in the map.
206- :return: A tuple of 1-bit WireVector carrying the result of the comparison,
207- followed by a named tuple containing the matched fields, if any.
206+ :return: A tuple of a 1-bit `` WireVector`` carrying the result of the comparison,
207+ followed by a ``namedtuple`` containing the matched fields, if any.
208208
209- This function will compare a multi-bit WireVector to a specified pattern of
209+ This function will compare a multi-bit `` WireVector`` to a specified pattern of
210210 bits, where some of the pattern can be "wildcard" bits. If any of the
211211 ``1`` or ``0`` values specified in the bitpattern fail to match the
212- WireVector during execution, a ``0`` will be produced, otherwise the value
212+ `` WireVector`` during execution, a ``0`` will be produced, otherwise the value
213213 carried on the wire will be ``1``. The wildcard characters can be any
214214 other alphanumeric character, with characters other than ``?`` having
215215 special functionality (see below). The string must have length equal to
216- the WireVector specified, although whitespace and underscore characters
216+ the `` WireVector`` specified, although whitespace and underscore characters
217217 will be ignored and can be used for pattern readability.
218218
219219 For all other characters besides ``1``, ``0``, or ``?``, a tuple of
220- WireVectors will be returned as the second return value. Each character
220+ `` WireVectors`` will be returned as the second return value. Each character
221221 will be treated as the name of a field, and non-consecutive fields with the
222222 same name will be concatenated together, left-to-right, into a single field
223223 in the resultant tuple. For example, ``01aa1?bbb11a`` will match a string
224224 such as ``010010100111``, and the resultant matched fields are::
225225
226226 (a, b) = (0b001, 0b100)
227227
228- where the ``a`` field is the concenation of bits 9, 8, and 0, and the ``b``
228+ where the ``a`` field is the concatenation of bits 9, 8, and 0, and the ``b``
229229 field is the concenation of bits 5, 4, and 3. Thus, arbitrary characters
230230 beside ``?`` act as wildcard characters for the purposes of matching, with
231- the additional benefit of returning the WireVectors corresponding to those
231+ the additional benefit of returning the `` WireVectors`` corresponding to those
232232 fields.
233233
234234 A prime example of this is for decoding instructions. Here we decode some
@@ -253,42 +253,49 @@ def match_bitpattern(w: WireVector, bitpattern: str,
253253
254254 m, _ = match_bitpattern(w, '0101') # basically the same as w == '0b0101'
255255 m, _ = match_bitpattern(w, '01?1') # m will be true when w is '0101' or '0111'
256- m, _ = match_bitpattern(w, '??01') # m be true when last two bits of w are '01'
256+ m, _ = match_bitpattern(w, '??01') # m will be true when last two bits of w are '01'
257257 m, _ = match_bitpattern(w, '??_0 1') # spaces/underscores are ignored, same as line above
258- m, (a, b) = match_pattern(w, '01aa1?bbb11a') # all bits with same letter make up same field
259- m, fs = match_pattern(w, '01aa1?bbb11a', {'a': 'foo', 'b': 'bar'}) # fields fs.foo, fs.bar
258+ # All bits with the same letter make up same field.
259+ m, (a, b) = match_bitpattern(w, '01aa1?bbb11a')
260+ # Fields will be named `fs.foo` and `fs.bar`.
261+ m, fs = match_bitpattern(w, '01aa1?bbb11a', {'a': 'foo', 'b': 'bar'})
260262
261263 """
262264 w = as_wires (w )
263265 if not isinstance (bitpattern , str ):
264266 raise PyrtlError ('bitpattern must be a string' )
265- nospace_string = '' . join ( bitpattern .replace ('_' , '' ). split () )
266- if len (w ) != len (nospace_string ):
267+ bitpattern = bitpattern .replace ("_" , "" ). replace ( " " , "" )
268+ if len (w ) != len (bitpattern ):
267269 raise PyrtlError ('bitpattern string different length than wirevector provided' )
268- lsb_first_string = nospace_string [::- 1 ] # flip so index 0 is lsb
270+ # Reverse ``bitpattern`` so index 0 is the least significant bit. This makes
271+ # ``w[i]`` and ``reversed_bitpattern[i]`` refer to the same bit ``i``.
272+ reversed_bitpattern = bitpattern [::- 1 ]
269273
270- zero_bits = [w [index ] for index , x in enumerate (lsb_first_string ) if x == '0' ]
271- one_bits = [w [index ] for index , x in enumerate (lsb_first_string ) if x == '1' ]
274+ zero_bits = [w [index ] for index , x in enumerate (reversed_bitpattern ) if x == '0' ]
275+ one_bits = [w [index ] for index , x in enumerate (reversed_bitpattern ) if x == '1' ]
272276 match = rtl_all (* one_bits ) & ~ rtl_any (* zero_bits )
273277
274- # Since only Python 3.7 and above guarantees maintaining insertion order in dictionaries,
275- # do all of this to make sure we can maintain the ordering in the returned Tuple.
276- # Order of fields is determined based on left-to-right ordering in original string.
277- def field_name (name ):
278+ def field_name (name : str ) -> str :
279+ """Retrieve a field's name from ``field_map``."""
278280 if field_map is not None :
279281 if name not in field_map :
280282 raise PyrtlError ('field_map argument has been given, '
281283 'but %s field is not present' % name )
282284 return field_map [name ]
283285 return name
284286
287+ # ``fields`` maps from ``field_name`` to a list of WireVectors that match
288+ # ``field_name``.
285289 fields = collections .defaultdict (list )
286- for i , c in enumerate (lsb_first_string ):
290+ for i , c in enumerate (reversed_bitpattern ):
287291 if c not in '01?' :
288292 fields [c ].append (w [i ])
289- fields = sorted (fields .items (), key = lambda m : nospace_string .index (m [0 ])) # now list of tuples
290- Fields = collections .namedtuple ('Fields' , ' ' .join (field_name (name ) for name , _ in fields ))
291- fields = Fields (** {field_name (k ): concat_list (l ) for k , l in fields })
293+ # Sort ``fields`` by each field's position in ``bitpattern`` and convert ``fields``
294+ # to a list of tuples.
295+ fields = sorted (fields .items (), key = lambda m : bitpattern .index (m [0 ]))
296+ Fields = collections .namedtuple ('Fields' , [field_name (name ) for name , _ in fields ])
297+ fields = Fields (** {field_name (name ): concat_list (wirevector_list )
298+ for name , wirevector_list in fields })
292299
293300 return MatchedFields (match , fields )
294301
0 commit comments