CIRCT  18.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  def __init__(self, next_state, *, loc=None, ip=None):
110  attributes = {
111  "nextState": FlatSymbolRefAttr.get(next_state),
112  }
113  super().__init__(
114  self.build_generic(attributes=attributes,
115  results=[],
116  operands=[],
117  successors=None,
118  regions=2,
119  loc=loc,
120  ip=ip))
121 
122  @staticmethod
123  def create(to_state):
124  op = fsm.TransitionOp(to_state)
125  return op
126 
127  def set_guard(self, guard_fn):
128  """Executes a function to generate a guard for the transition.
129  The function is executed within the guard region of this operation."""
130  guard_block = _get_or_add_single_block(self.guard)
131  with InsertionPoint(guard_block):
132  guard = guard_fn()
133  guard_type = support.type_to_pytype(guard.type)
134  if guard_type.width != 1:
135  raise ValueError('The guard must be a single bit')
136  fsm.ReturnOp(operand=guard)
137 
138 
139 @_ods_cext.register_operation(_Dialect, replace=True)
141 
142  def __init__(self, name, *, loc=None, ip=None):
143  attributes = {}
144  attributes["sym_name"] = StringAttr.get(name)
145 
146  OpView.__init__(
147  self,
148  self.build_generic(attributes=attributes,
149  results=[],
150  operands=[],
151  successors=None,
152  regions=2,
153  loc=loc,
154  ip=ip))
155 
156  @staticmethod
157  def create(name):
158  return fsm.StateOp(name)
159 
160  @property
161  def output(self):
162  return _get_or_add_single_block(super().output)
163 
164  @property
165  def transitions(self):
166  return _get_or_add_single_block(super().transitions)
167 
168 
169 @_ods_cext.register_operation(_Dialect, replace=True)
171 
172  @staticmethod
173  def create(*operands):
174  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:173
def __init__(self, name, *loc=None, ip=None)
Definition: fsm.py:142
def transitions(self)
Definition: fsm.py:165
def output(self)
Definition: fsm.py:161
def create(name)
Definition: fsm.py:157
def create(to_state)
Definition: fsm.py:123
def __init__(self, next_state, *loc=None, ip=None)
Definition: fsm.py:109
def set_guard(self, guard_fn)
Definition: fsm.py:127
def _get_or_add_single_block(region, args=[])
Definition: fsm.py:13