1#=========================================================================
2# StructuralTranslatorL1.py
3#=========================================================================
4# Author : Peitian Pan
5# Date   : March 24, 2019
6"""Provide L1 structural translator."""
7
8from collections import defaultdict, deque
9
10from pymtl3 import Placeholder
11from pymtl3.passes.rtlir import RTLIRDataType as rdt
12from pymtl3.passes.rtlir import RTLIRType as rt
13from pymtl3.passes.rtlir import StructuralRTLIRSignalExpr as sexp
14from pymtl3.passes.rtlir.structural.StructuralRTLIRGenL1Pass import (
15    StructuralRTLIRGenL1Pass,
16)
17from pymtl3.passes.rtlir.util.utility import get_component_full_name
18
19from ..BaseRTLIRTranslator import BaseRTLIRTranslator, TranslatorMetadata
20
21
22def gen_connections( top ):
23  """Return a collections of all connections of each instance in the
24     hierarchy whose top is `top`.
25  """
26  _inst_conns = defaultdict( set )
27
28  nets = top.get_all_value_nets()
29  adjs = top.get_signal_adjacency_dict()
30
31  for writer, net in nets:
32    S = deque( [ writer ] )
33    visited = {  writer  }
34    while S:
35      u = S.pop()
36      writer_host        = u.get_host_component()
37      writer_host_parent = writer_host.get_parent_object()
38      for v in adjs[u]:
39        if v not in visited:
40          visited.add( v )
41          S.append( v )
42          reader_host        = v.get_host_component()
43          reader_host_parent = reader_host.get_parent_object()
44
45          # Four possible cases for the reader and writer signals:
46          # 1.   They have the same host component. Both need
47          #       to be added to the host component.
48          # 2/3. One's host component is the parent of the other.
49          #       Both need to be added to the parent component.
50          # 4.   They have the same parent component.
51          #       Both need to be added to the parent component.
52
53          if writer_host is reader_host:
54            _inst_conns[writer_host].add( ( u, v ) )
55          elif writer_host_parent is reader_host:
56            _inst_conns[reader_host].add( ( u, v ) )
57          elif writer_host is reader_host_parent:
58            _inst_conns[writer_host].add( ( u, v ) )
59          elif writer_host_parent == reader_host_parent:
60            _inst_conns[writer_host_parent].add( ( u, v ) )
61          else:
62            raise TypeError( "unexpected connection type!" )
63
64  return _inst_conns
65
66class StructuralTranslatorL1( BaseRTLIRTranslator ):
67  def __init__( s, top ):
68    super().__init__( top )
69    # To avoid doing redundant computation, we generate the connections of
70    # the entire hierarchy once and only once here.
71    s.inst_conns = gen_connections( top )
72
73  def clear( s, tr_top ):
74    super().clear( tr_top )
75
76    # Set dummy tr_cfgs for testing
77    if not hasattr( s, 'tr_cfgs' ):
78      s.tr_cfgs = None
79
80    # Metadata namespace for RTLIR structural translator and the backend
81    # structural translator
82    s.structural = TranslatorMetadata()
83    s.s_backend = TranslatorMetadata()
84
85    # Generate metadata
86    s.gen_structural_trans_metadata( tr_top )
87
88    # Data type declaration
89    s.structural.decl_type_vector = {}
90    s.structural.decl_type_array  = {}
91
92  #-----------------------------------------------------------------------
93  # gen_structural_trans_metadata
94  #-----------------------------------------------------------------------
95
96  def _get_structural_rtlir_gen_pass( s ):
97    return StructuralRTLIRGenL1Pass
98
99  def gen_structural_trans_metadata( s, tr_top ):
100    tr_top.apply( s._get_structural_rtlir_gen_pass()( s.inst_conns ) )
101    s.structural.component_no_synthesis_no_clk = {}
102    s.structural.component_no_synthesis_no_reset = {}
103    s._gen_structural_no_clk_reset( tr_top )
104
105  def _gen_structural_no_clk_reset( s, m ):
106    if s.tr_cfgs:
107      s.structural.component_no_synthesis_no_clk[m] = s.tr_cfgs[m].no_synthesis_no_clk
108      s.structural.component_no_synthesis_no_reset[m] = s.tr_cfgs[m].no_synthesis_no_reset
109    else:
110      s.structural.component_no_synthesis_no_clk[m] = False
111      s.structural.component_no_synthesis_no_reset[m] = False
112    for _m in m.get_child_components(repr):
113      s._gen_structural_no_clk_reset( _m )
114
115  #-----------------------------------------------------------------------
116  # translate_structural
117  #-----------------------------------------------------------------------
118
119  def translate_structural( s, tr_top ):
120    """Translate structural part of top component under translation.
121
122    This function will only be called once during the whole translation
123    process.
124    """
125    # Component metadata
126    s.structural.component_is_top = {}
127    s.structural.component_name = {}
128    s.structural.component_file_info = {}
129    s.structural.component_full_name = {}
130    s.structural.component_unique_name = {}
131    s.structural.component_explicit_module_name = {}
132    s.structural.component_no_synthesis = {}
133
134    # Declarations
135    s.structural.decl_ports  = {}
136    s.structural.decl_wires  = {}
137    s.structural.decl_consts = {}
138
139    # Placeholder
140    s.structural.placeholder_src = {}
141
142    # Connections
143    s.structural.connections = {}
144    s._translate_structural( tr_top )
145
146  #-----------------------------------------------------------------------
147  # _translate_structural
148  #-----------------------------------------------------------------------
149
150  def _translate_structural( s, m ):
151    """Translate structural part of component m.
152
153    This method will be recursively applied to different components in the
154    hierarchy.
155    """
156    m_rtype = m.get_metadata( StructuralRTLIRGenL1Pass.rtlir_type )
157    s.structural.component_is_top[m] = m is s.tr_top
158    s.structural.component_name[m] = m_rtype.get_name()
159    s.structural.component_file_info[m] = m_rtype.get_file_info()
160    s.structural.component_full_name[m] = get_component_full_name(m_rtype)
161    s.structural.component_unique_name[m] = \
162        s.rtlir_tr_component_unique_name(m_rtype)
163    if s.tr_cfgs:
164      s.structural.component_explicit_module_name[m] = s.tr_cfgs[m].explicit_module_name
165    else:
166      s.structural.component_explicit_module_name[m] = ''
167    if s.tr_cfgs:
168      s.structural.component_no_synthesis[m] = s.tr_cfgs[m].no_synthesis
169    else:
170      s.structural.component_no_synthesis[m] = False
171
172    # Translate declarations of signals
173    s.translate_decls( m )
174
175    # Translate connections
176    s.translate_connections( m )
177
178    # Grab the pickled external source generated by PlaceholderPass
179    s.get_placeholder_src( m )
180
181  #-----------------------------------------------------------------------
182  # get_placeholder_src
183  #-----------------------------------------------------------------------
184
185  def get_placeholder_src( s, m ):
186    if isinstance( m, Placeholder ):
187      s.structural.placeholder_src[m] = s.rtlir_tr_placeholder_src( m )
188    else:
189      s.structural.placeholder_src[m] = ''
190
191  #-----------------------------------------------------------------------
192  # translate_decls
193  #-----------------------------------------------------------------------
194
195  def translate_decls( s, m ):
196    m_rtype  = m.get_metadata( StructuralRTLIRGenL1Pass.rtlir_type )
197
198    # Ports
199    port_decls = []
200    for port_id, rtype in m_rtype.get_ports_packed():
201      if isinstance( rtype, rt.Array ):
202        array_type = rtype
203        port_rtype = rtype.get_sub_type()
204      else:
205        array_type = None
206        port_rtype = rtype
207      port_decls.append(
208        s.rtlir_tr_port_decl(
209          s.rtlir_tr_var_id( port_id ),
210          port_rtype,
211          s.rtlir_tr_unpacked_array_type( array_type ),
212          s.rtlir_data_type_translation( m, port_rtype.get_dtype() )
213      ) )
214    s.structural.decl_ports[m] = s.rtlir_tr_port_decls( port_decls )
215
216    # Wires
217    wire_decls = []
218    for wire_id, rtype in m_rtype.get_wires_packed():
219      if isinstance( rtype, rt.Array ):
220        array_type = rtype
221        wire_rtype = rtype.get_sub_type()
222      else:
223        array_type = None
224        wire_rtype = rtype
225      wire_decls.append(
226        s.rtlir_tr_wire_decl(
227          s.rtlir_tr_var_id( wire_id ),
228          wire_rtype,
229          s.rtlir_tr_unpacked_array_type( array_type ),
230          s.rtlir_data_type_translation( m, wire_rtype.get_dtype() )
231      ) )
232    s.structural.decl_wires[m] = s.rtlir_tr_wire_decls( wire_decls )
233
234    # Consts
235    const_decls = []
236    if hasattr( s, "behavioral" ):
237      used_set = s.behavioral.accessed[m]
238    else:
239      used_set = None
240
241    for const_id, rtype, instance in m.get_metadata( StructuralRTLIRGenL1Pass.consts ):
242      if used_set is None or const_id in used_set:
243        if isinstance( rtype, rt.Array ):
244          array_type = rtype
245          const_rtype = rtype.get_sub_type()
246        else:
247          array_type = None
248          const_rtype = rtype
249        const_decls.append(
250          s.rtlir_tr_const_decl(
251            s.rtlir_tr_var_id( const_id ),
252            const_rtype,
253            s.rtlir_tr_unpacked_array_type( array_type ),
254            s.rtlir_data_type_translation( m, const_rtype.get_dtype() ),
255            instance
256        ) )
257    s.structural.decl_consts[m] = s.rtlir_tr_const_decls( const_decls )
258
259  #-----------------------------------------------------------------------
260  # translate_connections
261  #-----------------------------------------------------------------------
262
263  def translate_connections( s, m ):
264    connections = []
265    _connections = m.get_metadata( StructuralRTLIRGenL1Pass.connections )
266    for writer, reader in _connections:
267      connections.append( s.rtlir_tr_connection(
268        s.rtlir_signal_expr_translation( writer, m, 'writer' ),
269        s.rtlir_signal_expr_translation( reader, m, 'reader' )
270      ) )
271    s.structural.connections[m] = s.rtlir_tr_connections( connections )
272
273  #-----------------------------------------------------------------------
274  # rtlir_data_type_translation
275  #-----------------------------------------------------------------------
276
277  def rtlir_data_type_translation( s, m, dtype ):
278    """Translate an RTLIR data type into its backend representation."""
279    if isinstance( dtype, ( rdt.Vector, rdt.Bool ) ):
280      if isinstance( dtype, rdt.Bool ):
281        dtype = rdt.Vector( 1 )
282      ret = s.rtlir_tr_vector_dtype( dtype )
283      if dtype not in s.structural.decl_type_vector:
284        s.structural.decl_type_vector[ dtype ] = ret
285      return ret
286
287    else:
288      assert False, f"unsupported RTLIR dtype {dtype} at L1!"
289
290  #-----------------------------------------------------------------------
291  # rtlir_signal_expr_translation
292  #-----------------------------------------------------------------------
293
294  def rtlir_signal_expr_translation( s, expr, m, status = 'intermediate' ):
295    """Translate a signal expression in RTLIR into its backend representation.
296
297    Only the following operations are supported at L1:
298    sexp.CurComp, sexp.CurCompAttr, sexp.BitSelection, sexp.PartSelection, sexp.PortIndex,
299    sexp.WireIndex, sexp.ConstIndex
300    """
301    if isinstance( expr, sexp.CurComp ):
302      comp_id, comp_rtype = expr.get_component_id(), expr.get_rtype()
303      return s.rtlir_tr_current_comp( comp_id, comp_rtype, status )
304
305    elif isinstance( expr, sexp.CurCompAttr ):
306      return s.rtlir_tr_current_comp_attr(
307        s.rtlir_signal_expr_translation( expr.get_base(), m ),
308        expr.get_attr(), status )
309
310    elif isinstance( expr, sexp.PortIndex ):
311      return s.rtlir_tr_port_array_index(
312        s.rtlir_signal_expr_translation( expr.get_base(), m ),
313        expr.get_index(), status )
314
315    elif isinstance( expr, sexp.WireIndex ):
316      return s.rtlir_tr_wire_array_index(
317        s.rtlir_signal_expr_translation( expr.get_base(), m ),
318        expr.get_index(), status )
319
320    elif isinstance( expr, sexp.ConstIndex ):
321      return s.rtlir_tr_const_array_index(
322        s.rtlir_signal_expr_translation( expr.get_base(), m ),
323        expr.get_index(), status )
324
325    elif isinstance( expr, sexp.BitSelection ):
326      base = expr.get_base()
327      assert not isinstance(base, (sexp.PartSelection, sexp.BitSelection)), \
328        f'bit selection {expr} over bit/part selection {base} is not allowed!'
329      return s.rtlir_tr_bit_selection(
330        s.rtlir_signal_expr_translation( expr.get_base(), m ), expr.get_index(), status )
331
332    elif isinstance( expr, sexp.PartSelection ):
333      base = expr.get_base()
334      assert not isinstance(base, (sexp.PartSelection, sexp.BitSelection)), \
335        f'part selection {expr} over bit/part selection {base} is not allowed!'
336      start, stop = expr.get_slice()[0], expr.get_slice()[1]
337      return s.rtlir_tr_part_selection(
338        s.rtlir_signal_expr_translation( expr.get_base(), m ), start, stop, status )
339
340    elif isinstance( expr, sexp.ConstInstance ):
341      dtype = expr.get_rtype().get_dtype()
342      assert isinstance( dtype, rdt.Vector ), \
343          f'{dtype} is not supported at L1!'
344      return s.rtlir_tr_literal_number( dtype.get_length(), expr.get_value() )
345
346    # Other operations are not supported at L1
347    else:
348      assert False, f'{expr} is not supported at L1!'
349
350  #-----------------------------------------------------------------------
351  # Methods to be implemented by the backend translator
352  #-----------------------------------------------------------------------
353
354  # Placeholder
355  def rtlir_tr_placeholder_src( s, m ):
356    raise NotImplementedError()
357
358  # Data types
359  def rtlir_tr_vector_dtype( s, Type ):
360    raise NotImplementedError()
361
362  def rtlir_tr_unpacked_array_type( s, Type ):
363    raise NotImplementedError()
364
365  # Declarations
366  def rtlir_tr_port_decls( s, port_decls ):
367    raise NotImplementedError()
368
369  def rtlir_tr_port_decl( s, id_, rtype, array_type, dtype ):
370    raise NotImplementedError()
371
372  def rtlir_tr_wire_decls( s, wire_decls ):
373    raise NotImplementedError()
374
375  def rtlir_tr_wire_decl( s, id_, Type, array_type, dtype ):
376    raise NotImplementedError()
377
378  def rtlir_tr_const_decls( s, const_decls ):
379    raise NotImplementedError()
380
381  def rtlir_tr_const_decl( s, id_, Type, array_type, dtype, value ):
382    raise NotImplementedError()
383
384  # Connections
385  def rtlir_tr_connections( s, connections ):
386    raise NotImplementedError()
387
388  def rtlir_tr_connection( s, wr_signal, rd_signal ):
389    raise NotImplementedError()
390
391  # Signal operations
392  def rtlir_tr_bit_selection( s, base_signal, index, status ):
393    raise NotImplementedError()
394
395  def rtlir_tr_part_selection( s, base_signal, start, stop, status ):
396    raise NotImplementedError()
397
398  def rtlir_tr_port_array_index( s, base_signal, index, status ):
399    raise NotImplementedError()
400
401  def rtlir_tr_wire_array_index( s, base_signal, index, status ):
402    raise NotImplementedError()
403
404  def rtlir_tr_const_array_index( s, base_signal, index, status ):
405    raise NotImplementedError()
406
407  def rtlir_tr_current_comp_attr( s, base_signal, attr, status ):
408    raise NotImplementedError()
409
410  def rtlir_tr_current_comp( s, comp_id, comp_rtype, status ):
411    raise NotImplementedError()
412
413  # Miscs
414  def rtlir_tr_var_id( s, var_id ):
415    raise NotImplementedError()
416
417  def rtlir_tr_literal_number( s, nbits, value ):
418    raise NotImplementedError()
419
420  def rtlir_tr_component_unique_name( s, c_rtype ):
421    raise NotImplementedError()
422