22import itertools
33import re
44import os .path
5+ import enum as py_enum
56
67from ..hdl import *
7- from ..hdl ._repr import *
8- from ..hdl ._mem import MemoryInstance
9- from ..hdl ._ast import SignalDict , Slice , Operator
8+ from ..hdl ._ast import SignalDict
109from ._base import *
10+ from ._pyeval import eval_format , eval_value
1111from ._pyrtl import _FragmentCompiler
1212from ._pycoro import PyCoroProcess
1313from ._pyclock import PyClockProcess
@@ -21,23 +21,8 @@ class _VCDWriter:
2121 def decode_to_vcd (format , value ):
2222 return format .format (value ).expandtabs ().replace (" " , "_" )
2323
24- @staticmethod
25- def eval_field (field , signal , value ):
26- if isinstance (field , Signal ):
27- assert field is signal
28- return value
29- elif isinstance (field , Const ):
30- return field .value
31- elif isinstance (field , Slice ):
32- sub = _VCDWriter .eval_field (field .value , signal , value )
33- return (sub >> field .start ) & ((1 << (field .stop - field .start )) - 1 )
34- elif isinstance (field , Operator ) and field .operator in ('s' , 'u' ):
35- sub = _VCDWriter .eval_field (field .operands [0 ], signal , value )
36- return Const (sub , field .shape ()).value
37- else :
38- raise NotImplementedError # :nocov:
39-
40- def __init__ (self , design , * , vcd_file , gtkw_file = None , traces = (), fs_per_delta = 0 , processes = ()):
24+ def __init__ (self , state , design , * , vcd_file , gtkw_file = None , traces = (), fs_per_delta = 0 , processes = ()):
25+ self .state = state
4126 self .fs_per_delta = fs_per_delta
4227
4328 # Although pyvcd is a mandatory dependency, be resilient and import it as needed, so that
@@ -123,29 +108,21 @@ def __init__(self, design, *, vcd_file, gtkw_file=None, traces=(), fs_per_delta=
123108 for signal , names in itertools .chain (signal_names .items (), trace_names .items ()):
124109 self .vcd_signal_vars [signal ] = []
125110 self .gtkw_signal_names [signal ] = []
126- for repr in signal ._value_repr :
127- var_init = self .eval_field (repr .value , signal , signal .init )
128- if isinstance (repr .format , FormatInt ):
129- var_type = "wire"
130- var_size = repr .value .shape ().width
131- else :
132- var_type = "string"
133- var_size = 1
134- var_init = self .decode_to_vcd (repr .format , var_init )
135111
112+ def add_var (path , var_type , var_size , var_init , value ):
136113 vcd_var = None
137114 for (* var_scope , var_name ) in names :
138115 if re .search (r"[ \t\r\n]" , var_name ):
139116 raise NameError ("Signal '{}.{}' contains a whitespace character"
140117 .format ("." .join (var_scope ), var_name ))
141118
142119 field_name = var_name
143- for item in repr . path :
120+ for item in path :
144121 if isinstance (item , int ):
145122 field_name += f"[{ item } ]"
146123 else :
147124 field_name += f".{ item } "
148- if repr . path :
125+ if path :
149126 field_name = "\\ " + field_name
150127
151128 if vcd_var is None :
@@ -162,7 +139,35 @@ def __init__(self, design, *, vcd_file, gtkw_file=None, traces=(), fs_per_delta=
162139 scope = var_scope , name = field_name ,
163140 var = vcd_var )
164141
165- self .vcd_signal_vars [signal ].append ((vcd_var , repr ))
142+ self .vcd_signal_vars [signal ].append ((vcd_var , value ))
143+
144+ def add_wire_var (path , value ):
145+ add_var (path , "wire" , len (value ), eval_value (self .state , value ), value )
146+
147+ def add_format_var (path , fmt ):
148+ add_var (path , "string" , 1 , eval_format (self .state , fmt ), fmt )
149+
150+ def add_format (path , fmt ):
151+ if isinstance (fmt , Format .Struct ):
152+ add_wire_var (path , fmt ._value )
153+ for name , subfmt in fmt ._fields .items ():
154+ add_format (path + (name ,), subfmt )
155+ elif isinstance (fmt , Format .Array ):
156+ add_wire_var (path , fmt ._value )
157+ for idx , subfmt in enumerate (fmt ._fields ):
158+ add_format (path + (idx ,), subfmt )
159+ elif (isinstance (fmt , Format ) and
160+ len (fmt ._chunks ) == 1 and
161+ isinstance (fmt ._chunks [0 ], tuple ) and
162+ fmt ._chunks [0 ][1 ] == "" ):
163+ add_wire_var (path , fmt ._chunks [0 ][0 ])
164+ else :
165+ add_format_var (path , fmt )
166+
167+ if signal ._decoder is not None and not isinstance (signal ._decoder , py_enum .EnumMeta ):
168+ add_var ((), "string" , 1 , signal ._decoder (signal ._init ), signal ._decoder )
169+ else :
170+ add_format ((), signal ._format )
166171
167172 for memory , memory_name in memories .items ():
168173 self .vcd_memory_vars [memory ] = vcd_vars = []
@@ -205,11 +210,15 @@ def __init__(self, design, *, vcd_file, gtkw_file=None, traces=(), fs_per_delta=
205210 except KeyError :
206211 pass # try another name
207212
208- def update_signal (self , timestamp , signal , value ):
213+ def update_signal (self , timestamp , signal ):
209214 for (vcd_var , repr ) in self .vcd_signal_vars .get (signal , ()):
210- var_value = self .eval_field (repr .value , signal , value )
211- if not isinstance (repr .format , FormatInt ):
212- var_value = self .decode_to_vcd (repr .format , var_value )
215+ if isinstance (repr , Value ):
216+ var_value = eval_value (self .state , repr )
217+ elif isinstance (repr , (Format , Format .Enum )):
218+ var_value = eval_format (self .state , repr )
219+ else :
220+ # decoder
221+ var_value = repr (eval_value (self .state , signal ))
213222 self .vcd_writer .change (vcd_var , timestamp , var_value )
214223
215224 def update_memory (self , timestamp , memory , addr , value ):
@@ -512,7 +521,7 @@ def _step_rtl(self):
512521 if isinstance (change , _PySignalState ):
513522 signal_state = change
514523 vcd_writer .update_signal (now_plus_deltas ,
515- signal_state .signal , signal_state . curr )
524+ signal_state .signal )
516525 elif isinstance (change , _PyMemoryChange ):
517526 vcd_writer .update_memory (now_plus_deltas , change .state .memory ,
518527 change .addr , change .state .data [change .addr ])
@@ -559,7 +568,7 @@ def _now_plus_deltas(self, vcd_writer):
559568
560569 @contextmanager
561570 def write_vcd (self , * , vcd_file , gtkw_file , traces , fs_per_delta ):
562- vcd_writer = _VCDWriter (self ._design ,
571+ vcd_writer = _VCDWriter (self ._state , self . _design ,
563572 vcd_file = vcd_file , gtkw_file = gtkw_file , traces = traces , fs_per_delta = fs_per_delta ,
564573 processes = self ._testbenches )
565574 try :
0 commit comments