CIRCT  20.0.0git
fsm.py
Go to the documentation of this file.
1 # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2 # See https://llvm.org/LICENSE.txt for license information.
3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4 
5 from . import fsm as fsm
6 from .. import support
7 from ..dialects._ods_common import _cext as _ods_cext
8 from ..ir import *
9 from ._fsm_ops_gen import *
10 from ._fsm_ops_gen import _Dialect
11 
12 
13 def _get_or_add_single_block(region, args=[]):
14  if len(region.blocks) == 0:
15  region.blocks.append(*args)
16  return region.blocks[0]
17 
18 
19 @_ods_cext.register_operation(_Dialect, replace=True)
21 
22  def __init__(self,
23  name,
24  initial_state,
25  input_ports,
26  output_ports,
27  *,
28  attributes={},
29  loc=None,
30  ip=None):
31  attributes["sym_name"] = StringAttr.get(name)
32  attributes["initialState"] = StringAttr.get(initial_state)
33 
34  input_types = []
35  output_types = []
36  for (i, (_, port_type)) in enumerate(input_ports):
37  input_types.append(port_type)
38 
39  for (i, (_, port_type)) in enumerate(output_ports):
40  output_types.append(port_type)
41 
42  attributes["function_type"] = TypeAttr.get(
43  FunctionType.get(inputs=input_types, results=output_types))
44 
45  OpView.__init__(
46  self,
47  self.build_generic(attributes=attributes,
48  results=[],
49  operands=[],
50  successors=None,
51  regions=1,
52  loc=loc,
53  ip=ip))
54 
55  _get_or_add_single_block(self.body, self.typetype.inputs)
56 
57  @property
58  def type(self):
59  return FunctionType(TypeAttr(self.attributes["function_type"]).value)
60 
61  def instantiate(self, name: str, loc=None, ip=None, **kwargs):
62  """ FSM Instantiation function"""
63  in_names = support.attribute_to_var(self.attributes['in_names'])
64  inputs = [kwargs[port].value for port in in_names]
65 
66  # Clock and resets are not part of the input ports of the FSM, but
67  # it is at the point of `fsm.hw_instance` instantiation that they
68  # must be connected.
69  # Attach backedges to these, and associate these backedges to the operation.
70  # They can then be accessed at the point of instantiation and assigned.
71  clock = support.BackedgeBuilder().create(
72  IntegerType.get_signed(1),
73  StringAttr(self.attributes['clock_name']).value, self)
74  reset = support.BackedgeBuilder().create(
75  IntegerType.get_signed(1),
76  StringAttr(self.attributes['reset_name']).value, self)
77 
78  op = fsm.HWInstanceOp(outputs=self.typetype.results,
79  inputs=inputs,
80  sym_name=StringAttr.get(name),
81  machine=FlatSymbolRefAttr.get(self.sym_name.value),
82  clock=clock.result,
83  reset=reset.result if reset else None,
84  loc=loc,
85  ip=ip)
86  op.backedges = {}
87 
88  def set_OpOperand(name, backedge):
89  index = None
90  for i, operand in enumerate(op.operands):
91  if operand == backedge.result:
92  index = i
93  break
94  assert index is not None
95  op_operand = support.OpOperand(op, index, op.operands[index], op)
96  setattr(op, f'_{name}_backedge', op_operand)
97  op.backedges[i] = backedge
98 
99  set_OpOperand('clock', clock)
100  if reset:
101  set_OpOperand('reset', reset)
102 
103  return op
104 
105 
106 @_ods_cext.register_operation(_Dialect, replace=True)
108 
109  @staticmethod
110  def create(to_state):
111  op = fsm.TransitionOp(to_state)
112  return op
113 
114  def set_guard(self, guard_fn):
115  """Executes a function to generate a guard for the transition.
116  The function is executed within the guard region of this operation."""
117  guard_block = _get_or_add_single_block(self.guard)
118  with InsertionPoint(guard_block):
119  guard = guard_fn()
120  guard_type = support.type_to_pytype(guard.type)
121  if guard_type.width != 1:
122  raise ValueError('The guard must be a single bit')
123  fsm.ReturnOp(operand=guard)
124 
125 
126 @_ods_cext.register_operation(_Dialect, replace=True)
128 
129  def __init__(self, name, *, loc=None, ip=None):
130  attributes = {}
131  attributes["sym_name"] = StringAttr.get(name)
132 
133  OpView.__init__(
134  self,
135  self.build_generic(attributes=attributes,
136  results=[],
137  operands=[],
138  successors=None,
139  regions=2,
140  loc=loc,
141  ip=ip))
142 
143  @staticmethod
144  def create(name):
145  return fsm.StateOp(name)
146 
147  @property
148  def output(self):
149  return _get_or_add_single_block(super().output)
150 
151  @property
152  def transitions(self):
153  return _get_or_add_single_block(super().transitions)
154 
155 
156 @_ods_cext.register_operation(_Dialect, replace=True)
158 
159  @staticmethod
160  def create(*operands):
161  return fsm.OutputOp(operands)
def instantiate(self, str name, loc=None, ip=None, **kwargs)
Definition: fsm.py:61
def type(self)
Definition: fsm.py:58
def __init__(self, name, initial_state, input_ports, output_ports, *attributes={}, loc=None, ip=None)
Definition: fsm.py:30
def create(*operands)
Definition: fsm.py:160
def __init__(self, name, *loc=None, ip=None)
Definition: fsm.py:129
def transitions(self)
Definition: fsm.py:152
def output(self)
Definition: fsm.py:148
def create(name)
Definition: fsm.py:144
def create(to_state)
Definition: fsm.py:110
def set_guard(self, guard_fn)
Definition: fsm.py:114
def _get_or_add_single_block(region, args=[])
Definition: fsm.py:13