22"""Write Value Change Dump files.
24This module provides :class:`VCDWriter` for writing VCD files.
27from collections
import OrderedDict
29from numbers
import Number
32from itertools
import zip_longest
36 """Indicating a :class:`VCDWriter` method was called in the wrong phase.
38 For example, calling :meth:`register_var()` after :meth:`close()` will
45 """Value Change Dump writer.
47 A VCD file captures time-ordered changes to the value of variables.
49 :param file file: A file-like object to write the VCD data.
51 Scale of the VCD timestamps. The timescale may either be a string or a
52 tuple containing an (int, str) pair.
53 :type timescale: str, tuple
54 :param str date: Optional `$date` string used
in the VCD header.
55 :param str comment: Optional `$comment` string used
in the VCD header.
56 :param str version: Optional `$version` string used
in the VCD header.
57 :param str default_scope_type: Scope type
for scopes where
59 :param str scope_sep: Separator
for scopes specified
as strings.
60 :param int init_timestamp: The initial timestamp. default=0
61 :raises ValueError:
for invalid timescale values
66 SCOPE_TYPES = ['begin',
'fork',
'function',
'module',
'task']
69 VAR_TYPES = [
'event',
'integer',
'parameter',
'real',
'realtime',
'reg',
70 'supply0',
'supply1',
'time',
'tri',
'triand',
'trior',
71 'trireg',
'tri0',
'tri1',
'wand',
'wire',
'wor']
74 TIMESCALE_NUMS = [1, 10, 100]
77 TIMESCALE_UNITS = [
's',
'ms',
'us',
'ns',
'ps',
'fs']
79 def __init__(self, file, timescale='1 us', date=None, comment='',
80 version='', default_scope_type='module', scope_sep='.',
81 check_values=True, init_timestamp=0):
82 """Initialization of VCDWriter"""
88 '$date': str(datetime.datetime.now())
if date
is None else date,
93 raise ValueError(f
'Invalid default scope type ({default_scope_type})')
120 """Set the scope_type for a given scope.
122 The scope's type may be set to one of the valid :const:`SCOPE_TYPES`.
123 VCD viewer applications may display different scope types differently.
125 :param scope: The scope to set the type of.
126 :type scope: str or sequence of str
127 :param str scope_type: A valid scope type string.
128 :raises ValueError:
for invalid `scope_type`
131 if scope_type
is not None and scope_type
not in self.
SCOPE_TYPES:
132 raise ValueError(f
'Invalid scope_type "{scope_type}"')
138 """Register a VCD variable and return function to change value.
140 All VCD variables must be registered prior to any value changes.
144 The variable `name` differs from the variable
's `ident`
145 (identifier). The `name` (also known as `ref`)
is meant to refer to
146 the variable name
in the code being traced
and is visible
in VCD
147 viewer applications. The `ident`, however,
is only used within the
148 VCD file
and can be auto-generated (by specifying ``ident=
None``)
149 for most applications.
151 :param scope: The hierarchical scope that the variable belongs within.
152 :type scope: str
or sequence of str
153 :param str name: Name of the variable.
154 :param str var_type: One of :const:`VAR_TYPES`.
156 Size,
in bits, of the variable. The *size* may be expressed
as an
157 int
or,
for vector variable types, a tuple of int. When the size
is
158 expressed
as a tuple, the *value* passed to :meth:`
change()` must
159 also be a tuple of same arity
as the *size* tuple. Some variable
160 types (
'integer',
'real',
'realtime',
and 'event') have a default
161 size
and thus *size* may be ``
None``
for those variable types.
162 :type size: int
or tuple(int)
or None
163 :param init: Optional initial value; defaults to
'x'.
164 :param str ident: Optional identifier
for use
in the VCD stream.
165 :raises VCDPhaseError:
if any values have been changed
166 :raises ValueError:
for invalid var_type value
167 :raises TypeError:
for invalid parameter types
168 :raises KeyError:
for duplicate var name
169 :returns: :
class:`Variable` instance appropriate
for use
with
178 raise ValueError(f
'Invalid var_type "{var_type}"')
183 if name
in scope_names:
184 raise KeyError(f
'Duplicate var {name} in scope {scope}')
190 if var_type
in [
'integer',
'real',
'realtime']:
192 elif var_type ==
'event':
196 f
'Must supply size for {var_type} var_type')
198 if isinstance(size, Sequence):
204 var_str = f
'$var {var_type} {var_size} {ident} {name} $end'
207 if var_type ==
'real':
209 elif isinstance(size, tuple):
210 init = tuple(
'x' * len(size))
216 elif var_type ==
'real':
221 if var_type !=
'event':
227 scope_names.append(name)
232 """Suspend dumping to VCD file."""
239 """Stop dumping to VCD file."""
240 print(
'#' + str(int(timestamp)), file=self.
_ofile)
241 print(
'$dumpoff', file=self.
_ofile)
243 if val_str[0] ==
'b':
244 print(
'bx', ident, file=self.
_ofile)
245 elif val_str[0] ==
'r':
248 print(
'x', ident, sep=
'', file=self.
_ofile)
249 print(
'$end', file=self.
_ofile)
252 """Resume dumping to VCD file."""
254 print(
'#' + str(int(timestamp)), file=self.
_ofile)
255 """set dump_values"""
260 """Dump values to VCD file."""
261 print(keyword, file=self.
_ofile)
264 sep=
'\n', file=self.
_ofile)
265 print(
'$end', file=self.
_ofile)
268 """Change variable's value in VCD stream.
270 This is the fundamental behavior of a :
class:`VCDWriter` instance. Each
271 time a variable
's value changes, this method should be called.
273 The *timestamp* must be in-order relative to timestamps
from previous
274 calls to :meth:`
change()`. It
is okay to call :meth:`
change()` multiple
275 times
with the same *timestamp*, but never
with a past *timestamp*.
279 :meth:`
change()` may be called multiple times before the timestamp
280 progresses past 0. The last value change
for each variable will go
281 into the $dumpvars section.
283 :param Variable var: :
class:`Variable` instance (i.e.
from
285 :param int timestamp: Current simulation time.
287 New value
for *var*. For :
class:`VectorVariable`,
if the variable
's
288 *size* is a tuple, then *value* must be a tuple of the same arity.
290 :raises ValueError:
if the value
is not valid
for *var*.
291 :raises VCDPhaseError:
if the timestamp
is out of order
or the
292 :
class:`VCDWriter` instance
is closed.
301 ts_int = int(timestamp)
307 print(
'#', ts_int, sep=
'', file=self.
_ofile)
311 print(val_str, file=self.
_ofile)
316 """get scope tuple function of the VCDWrite"""
317 if isinstance(scope, str):
319 if isinstance(scope, (list, tuple)):
322 raise TypeError(f
'Invalid scope {scope}')
326 """check time scale function of the VCDWrite"""
327 if isinstance(timescale, (list, tuple)):
328 if len(timescale) == 1:
331 elif len(timescale) == 2:
332 num, unit = timescale
334 raise ValueError(f
'Invalid timescale num {num}')
337 raise ValueError(f
'Invalid timescale {timescale}')
338 elif isinstance(timescale, str):
345 if timescale.startswith(num_str):
346 unit = timescale[len(num_str):].lstrip(
' ')
350 f
'Invalid timescale num {timescale}')
352 raise TypeError(f
'Invalid timescale type {type(timescale).__name__}')
354 raise ValueError(f
'Invalid timescale unit "{unit}"')
355 return ' '.join([num_str, unit])
358 """enter of VCDWriter"""
362 """exit of VCDWriter"""
368 Any buffered VCD data is flushed to the output file. After
369 :meth:`
close()`, no variable registration
or value changes will be
372 :param int timestamp: optional final timestamp to insert into VCD
377 The output file
is not automatically closed. It
is up to the user
378 to ensure the output file
is closed after the :
class:`VCDWriter`
383 self.
flush(timestamp)
387 """Flush any buffered VCD data to output file.
389 If the VCD header has not already been written, calling `
flush()` will
390 force the header to be written thus disallowing any further variable
393 :param int timestamp: optional timestamp to insert into VCD stream.
400 if timestamp
is not None and timestamp > self.
_timestamp:
401 print(
"#", int(timestamp), sep=
'', file=self.
_ofile)
405 """generate header for VCDWriter"""
409 lines = kwvalue.split(
'\n')
411 yield f
'{kwname} {lines[0]} $end'
422 for i, (prev, this)
in enumerate(zip_longest(prev_scope, scope)):
424 for _
in prev_scope[i:]:
425 yield '$upscope $end'
427 for j, name
in enumerate(scope[i:]):
430 yield f
'$scope {scope_type} {name} $end'
433 assert scope != prev_scope
440 yield '$upscope $end'
442 yield '$enddefinitions $end'
445 """finalize registration of VCDWriter"""
462 """VCD variable details needed to call :meth:`VCDWriter.change()`."""
465 __slots__ = (
'ident',
'type',
'size')
468 """Initialization of Variable function"""
477 """Format value change for use in VCD stream."""
478 raise NotImplementedError
482 """One-bit VCD scalar.
484 This is a 4-state variable
and thus may have values of 0, 1,
'z',
or 'x'.
492 """Format scalar value change for VCD stream.
494 :param value: 1-bit (4-state) scalar value.
495 :type value: str, bool, int, or None
496 :raises ValueError:
for invalid *value*.
497 :returns: string representing value change
for use
in a VCD stream.
500 if isinstance(value, str):
501 if check
and (len(value) != 1
or value
not in '01xzXZ'):
502 raise ValueError(f
'Invalid scalar value ({value})')
503 return value + self.
ident
505 return 'z' + self.
ident
507 return '1' + self.
ident
509 return '0' + self.
ident
513 """Real (IEEE-754 double-precision floating point) variable.
515 Values must be numeric and cannot be
'x' or 'z' states.
523 """Format real value change for VCD stream.
525 :param value: Numeric changed value.
526 :param type: float or int
527 :raises ValueError:
for invalid real *value*.
528 :returns: string representing value change
for use
in a VCD stream.
531 if not check
or isinstance(value, Number):
532 return f
'r{value:.16g} {self.ident}'
534 raise ValueError(f
'Invalid real value ({value})')
538 """Bit vector variable type.
540 This is for the various non-scalar
and non-real variable types including
541 integer, register, wire, etc.
549 """Format value change for VCD stream.
551 :param value: New value for the variable.
552 :types value: int, str,
or None
553 :raises ValueError:
for *some* invalid values.
555 A *value* of `
None`
is the same
as `
'z'`.
559 If *value*
is of type :py:
class:`str`, all characters must be one
560 of `
'01xzXZ'`. For the sake of performance, checking **
is not**
561 done to ensure value strings only contain conforming characters.
562 Thus it
is possible to produce invalid VCD streams
with invalid
566 if isinstance(self.
size, tuple):
572 for i, (v, size)
in enumerate(zip(reversed(value),
573 reversed(self.
size))):
576 vstr_list.insert(0, vstr)
577 vstr_len += len(vstr)
579 leftc = vstr_list[0][0]
581 if len(vstr) > 1
or ((rightc != leftc
or leftc ==
'1')
and
582 (rightc !=
'0' or leftc !=
'1')):
583 extendc =
'0' if leftc ==
'1' else leftc
584 extend_size = size_sum - vstr_len
585 vstr_list.insert(0, extendc * extend_size)
586 vstr_list.insert(0, vstr)
587 vstr_len += extend_size + len(vstr)
589 value_str =
''.join(vstr_list)
592 return f
'b{value_str} {self.ident}'
595 """format value function of VCDWriter"""
596 if isinstance(value, int):
598 if check
and (-value > (max_val >> 1)
or value >= max_val):
599 raise ValueError(f
'Value ({value}) not representable in {size} bits')
602 return format(value,
'b')
606 if check
and (
not isinstance(value, str)
or
608 any(c
not in '01xzXZ-' for c
in value)):
609 raise ValueError(f
'Invalid vector value ({value})')
def format_value(self, value, check=True)
def format_value(self, value, check=True)
_registering
set registering
def __exit__(self, exc_type, exc_val, exc_tb)
def _check_timescale(cls, timescale)
def _dump_values(self, keyword)
def dump_off(self, timestamp)
_next_var_id
set next_var_id
def _finalize_registration(self)
list TIMESCALE_NUMS
Valid timescale numbers.
def dump_on(self, timestamp)
_scope_types
set scopr_types
def change(self, var, timestamp, value)
def __init__(self, file, timescale='1 us', date=None, comment='', version='', default_scope_type='module', scope_sep='.', check_values=True, init_timestamp=0)
list TIMESCALE_UNITS
Valid timescale units.
list VAR_TYPES
Valid VCD variable types.
_check_values
set check_values
def register_var(self, scope, name, var_type, size=None, init=None, ident=None)
def close(self, timestamp=None)
def flush(self, timestamp=None)
_scope_var_names
set scope_var_names
_default_scope_type
set default_scope_type
def _dump_off(self, timestamp)
def set_scope_type(self, scope, scope_type)
list SCOPE_TYPES
Valid VCD scope types.
def _get_scope_tuple(self, scope)
_scope_var_strs
set scope_var_strs
_ident_values
set ident_values
_header_keywords
header keywords
ident
Identifier used in VCD output stream.
type
VCD variable type; one of :const:VCDWriter.VAR_TYPES.
size
Size, in bits, of variable.
def __init__(self, ident, type, size)
def format_value(self, value, check=True)
def _format_value(self, value, size, check)
def format_value(self, value, check=True)