1#=========================================================================
2# VStructuralTranslatorL1.py
3#=========================================================================
4"""Provide SystemVerilog structural translator implementation."""
5
6
7from pymtl3.datatypes import Bits
8from pymtl3.passes.backends.generic.structural.StructuralTranslatorL1 import (
9    StructuralTranslatorL1,
10)
11from pymtl3.passes.rtlir import RTLIRDataType as rdt
12from pymtl3.passes.rtlir import RTLIRType as rt
13
14from ...errors import VerilogPlaceholderError, VerilogReservedKeywordError
15from ...util.utility import get_component_unique_name, make_indent, pretty_concat
16
17
18class VStructuralTranslatorL1( StructuralTranslatorL1 ):
19
20  def check_decl( s, name, msg ):
21    if s.is_verilog_reserved( name ):
22      raise VerilogReservedKeywordError( name, msg )
23
24  #-----------------------------------------------------------------------
25  # Placeholder
26  #-----------------------------------------------------------------------
27
28  def rtlir_tr_placeholder_src( s, m ):
29    try:
30      ph_cfg = m.get_metadata( s._placeholder_pass.placeholder_config )
31      if m is s.tr_top:
32        # If this placeholder is a top level module, use the wrapper
33        # template to support explicit module name.
34        if s.tr_cfgs and s.tr_cfgs[m].explicit_module_name:
35          module_name = s.tr_cfgs[m].explicit_module_name
36        else:
37          module_name = ph_cfg.pickled_top_module
38          s._mangled_placeholder_top_module_name = module_name
39
40        if module_name == ph_cfg.top_module:
41          raise VerilogPlaceholderError(m,
42              f"failed to create wrapper for the given object because the same "
43              f"name {module_name} is used for both the Verilog top module and "
44              f"the wrapper. Please specify a different name through the "
45              f"`explicit_module_name` option of TranslationConfigs.")
46
47        # Read the dependency of the placeholder
48        nlines     = ph_cfg.pickled_wrapper_nlines
49        dependency = '\n'.join( ph_cfg.pickled_source.splitlines()[:-nlines] )
50
51        # Create the placeholder wrapper from the ph_cfg metadata
52        wrapper = ph_cfg.pickled_wrapper_template.format(top_module_name=module_name)
53
54        return dependency + wrapper
55
56      else:
57        # Otherwise use the pickled placeholder source
58        return ph_cfg.pickled_source
59    except (AttributeError, OSError):
60      # Forgot to apply VerilogPlaceholderPass?
61      raise Exception(
62                f"error while translating placeholder {m}:\n"
63                f"- Did you forget to apply the correct PlaceholderPass(e.g. VerilogPlaceholderPass)?" )
64
65  #-----------------------------------------------------------------------
66  # Data types
67  #-----------------------------------------------------------------------
68
69  def rtlir_tr_vector_dtype( s, dtype ):
70    msb = dtype.get_length() - 1
71    return {
72      'def'  : '',
73      'nbits' : dtype.get_length(),
74      'data_type' : 'logic',
75      'packed_type' : f'[{msb}:0]',
76      'unpacked_type' : '',
77      'raw_dtype' : dtype
78    }
79
80  def rtlir_tr_unpacked_array_type( s, Type ):
81    if Type is None:
82      return { 'def' : '', 'unpacked_type' : '', 'n_dim':[] }
83    else:
84      array_dim = "".join( f"[0:{size-1}]" for size in Type.get_dim_sizes() )
85      return {
86        'def'  : '',
87        'unpacked_type' : array_dim,
88        'n_dim' : Type.get_dim_sizes()
89      }
90
91  #-----------------------------------------------------------------------
92  # Declarations
93  #-----------------------------------------------------------------------
94
95  def rtlir_tr_port_decls( s, port_decls ):
96    make_indent( port_decls, 1 )
97    return ',\n'.join( port_decls )
98
99  def rtlir_tr_port_decl( s, id_, Type, array_type, dtype ):
100    _dtype = Type.get_dtype()
101    direction = Type.get_direction()
102    if direction == 'input':
103      direction += ' '
104    if array_type:
105      template = "Note: port {id_} has data type {_dtype}"
106    else:
107      n_dim = array_type['n_dim']
108      template = "Note: {n_dim} array of ports {id_} has data type {_dtype}"
109    s.check_decl( id_, template.format( **locals() ) )
110    return pretty_concat( direction, dtype['data_type'], dtype['packed_type'],
111              id_, array_type['unpacked_type'] )
112
113  def rtlir_tr_wire_decls( s, wire_decls ):
114    make_indent( wire_decls, 1 )
115    return '\n'.join( wire_decls )
116
117  def rtlir_tr_wire_decl( s, id_, Type, array_type, dtype ):
118    _dtype = Type.get_dtype()
119    if array_type:
120      template = "Note: wire {id_} has data type {_dtype}"
121    else:
122      n_dim = array_type['n_dim']
123      template = "Note: {n_dim} array of wires {id_} has data type {_dtype}"
124    s.check_decl( id_, template.format( **locals() ) )
125    return pretty_concat( dtype['data_type'], dtype['packed_type'],
126              id_, array_type['unpacked_type'], ';' )
127
128  def rtlir_tr_const_decls( s, const_decls ):
129    make_indent( const_decls, 1 )
130    return '\n'.join( const_decls )
131
132  def gen_array_param( s, n_dim, dtype, array ):
133    if not n_dim:
134      if isinstance( dtype, rdt.Vector ):
135        return s._literal_number( dtype.get_length(), array )
136      else:
137        assert False, f'{array} is not an integer or a BitStruct!'
138    else:
139      ret = []
140      for _idx, idx in enumerate( range( n_dim[0] ) ):
141        ret.append( s.gen_array_param( n_dim[1:], dtype, array[idx] ) )
142      return f"'{{ {', '.join(ret)} }}"
143
144  def rtlir_tr_const_decl( s, id_, Type, array_type, dtype, value ):
145    _dtype = Type.get_dtype()
146    if array_type:
147      template = "Note: constant {id_} has data type {_dtype}"
148    else:
149      n_dim = array_type['n_dim']
150      template = "Note: {n_dim} array of constants {id_} has data type {_dtype}"
151    s.check_decl( id_, template.format( **locals() ) )
152    _dtype = pretty_concat(dtype['data_type'], dtype['packed_type'], id_, array_type['unpacked_type'])
153    _value = s.gen_array_param( array_type['n_dim'], dtype['raw_dtype'], value )
154
155    return f'localparam {_dtype} = {_value};'
156
157  #-----------------------------------------------------------------------
158  # Connections
159  #-----------------------------------------------------------------------
160
161  def rtlir_tr_connections( s, connections ):
162    make_indent( connections, 1 )
163    return '\n'.join( connections )
164
165  def rtlir_tr_connection( s, wr_signal, rd_signal ):
166    return f'assign {rd_signal} = {wr_signal};'
167
168  #-----------------------------------------------------------------------
169  # Signal operations
170  #-----------------------------------------------------------------------
171
172  def rtlir_tr_bit_selection( s, base_signal, index, status ):
173    # Bit selection
174    return s._rtlir_tr_process_unpacked(
175              f'{base_signal}[{index}]',
176              f'{base_signal}{{}}[{index}]',
177              status, ('status', 'unpacked') )
178
179  def rtlir_tr_part_selection( s, base_signal, start, stop, status ):
180    # Part selection
181    return s._rtlir_tr_process_unpacked(
182              f'{base_signal}[{stop-1}:{start}]',
183              f'{base_signal}{{}}[{stop-1}:{start}]',
184              status, ('status', 'unpacked') )
185
186  def rtlir_tr_port_array_index( s, base_signal, index, status ):
187    return s._rtlir_tr_process_unpacked(
188              f'{base_signal}[{index}]',
189              f'{base_signal}{{}}[{index}]',
190              status, ('status', 'unpacked') )
191
192  def rtlir_tr_wire_array_index( s, base_signal, index, status ):
193    return f'{base_signal}[{index}]'
194
195  def rtlir_tr_const_array_index( s, base_signal, index, status ):
196    return f'{base_signal}[{index}]'
197
198  def rtlir_tr_current_comp_attr( s, base_signal, attr, status ):
199    return f'{attr}'
200
201  def rtlir_tr_current_comp( s, comp_id, comp_rtype, status ):
202    return ''
203
204  def _rtlir_tr_process_unpacked( s, signal, signal_tplt, status, enable ):
205    if (status in ('reader', 'writer') and 'status' in enable) or \
206       (s._rtlir_tr_unpacked_q and 'unpacked' in enable):
207      ret = signal_tplt.format(''.join(
208                [f'[{i}]' for i in list(s._rtlir_tr_unpacked_q)]))
209      s._rtlir_tr_unpacked_q.clear()
210      return ret
211    else:
212      return signal
213
214  #-----------------------------------------------------------------------
215  # Miscs
216  #-----------------------------------------------------------------------
217
218  def rtlir_tr_var_id( s, var_id ):
219    return var_id.replace( '[', '__' ).replace( ']', '' )
220
221  def _literal_number( s, nbits, value ):
222    return f"{nbits}'d{int(value)}"
223
224  def rtlir_tr_literal_number( s, nbits, value ):
225    return s._literal_number( nbits, value )
226
227  def rtlir_tr_component_unique_name( s, c_rtype ):
228    return get_component_unique_name( c_rtype )
229