Ejemplo n.º 1
0
    def __init__(self, m, name, clk, rst=None, nohook=False):
        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst

        self.tmp_count = 0
        self.delay_amount = 0
        self.delayed_body = collections.defaultdict(list)
        self.prev_dict = collections.OrderedDict()
        self.body = []

        self.dst_var = collections.OrderedDict()
        self.dst_visitor = SubstDstVisitor()
        self.reset_visitor = ResetVisitor()

        self.done = False

        self.last_cond = []
        self.last_kwargs = {}
        self.last_if_statement = None
        self.elif_cond = None
        self.next_kwargs = {}

        if not nohook:
            self.m.add_hook(self.make_always)
Ejemplo n.º 2
0
    def __init__(self, m, name, clk, rst=None, nohook=False, as_module=False):
        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst

        self.tmp_count = 0
        self.delay_amount = 0
        self.delayed_body = collections.defaultdict(list)
        self.prev_dict = collections.OrderedDict()
        self.body = []

        self.dst_var = collections.OrderedDict()
        self.dst_visitor = SubstDstVisitor()
        self.reset_visitor = ResetVisitor()

        self.done = False

        self.last_cond = []
        self.last_kwargs = {}
        self.last_if_statement = None
        self.elif_cond = None
        self.next_kwargs = {}

        self.as_module = as_module

        if not nohook:
            self.m.add_hook(self.implement)
Ejemplo n.º 3
0
    def __init__(self,
                 m,
                 name,
                 clk,
                 rst,
                 width=32,
                 initname='init',
                 nohook=False,
                 as_module=False):
        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst
        self.width = width
        self.state_count = 0
        self.state = self.m.Reg(name, width)  # set initval later

        self.mark = collections.OrderedDict()  # key:index
        self._set_mark(0, self.name + '_' + initname)
        self.state.initval = self._get_mark(0)

        self.body = collections.defaultdict(list)
        self.jump = collections.defaultdict(list)

        self.delay_amount = 0
        self.delayed_state = collections.OrderedDict()  # key:delay
        self.delayed_body = collections.defaultdict(
            functools.partial(collections.defaultdict, list))  # key:delay
        self.delayed_cond = collections.OrderedDict()  # key:name
        self.tmp_count = 0

        self.dst_var = collections.OrderedDict()
        self.dst_visitor = SubstDstVisitor()
        self.reset_visitor = ResetVisitor()

        self.seq = Seq(self.m, self.name + '_par', clk, rst, nohook=True)

        self.done = False

        self.last_cond = []
        self.last_kwargs = {}
        self.last_if_statement = None
        self.elif_cond = None
        self.next_kwargs = {}

        self.as_module = as_module

        if not nohook:
            self.m.add_hook(self.implement)
Ejemplo n.º 4
0
    def __init__(self, m, name, clk, rst, width=32, initname='init',
                 nohook=False, as_module=False):
        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst
        self.width = width
        self.state_count = 0
        self.state = self.m.Reg(name, width)  # set initval later

        self.mark = collections.OrderedDict()  # key:index
        self._set_mark(0, self.name + '_' + initname)
        self.state.initval = self._get_mark(0)

        self.body = collections.defaultdict(list)
        self.jump = collections.defaultdict(list)

        self.delay_amount = 0
        self.delayed_state = collections.OrderedDict()  # key:delay
        self.delayed_body = collections.defaultdict(
            functools.partial(collections.defaultdict, list))  # key:delay
        self.delayed_cond = collections.OrderedDict()  # key:name
        self.tmp_count = 0

        self.dst_var = collections.OrderedDict()
        self.dst_visitor = SubstDstVisitor()
        self.reset_visitor = ResetVisitor()

        self.seq = Seq(self.m, self.name + '_par', clk, rst, nohook=True)

        self.done = False

        self.last_cond = []
        self.last_kwargs = {}
        self.last_if_statement = None
        self.elif_cond = None
        self.next_kwargs = {}

        self.as_module = as_module

        if not nohook:
            self.m.add_hook(self.implement)
Ejemplo n.º 5
0
class Seq(vtypes.VeriloggenNode):
    """ Sequential Logic Manager """

    def __init__(self, m, name, clk, rst=None, nohook=False):
        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst

        self.tmp_count = 0
        self.delay_amount = 0
        self.delayed_body = collections.defaultdict(list)
        self.prev_dict = collections.OrderedDict()
        self.body = []

        self.dst_var = collections.OrderedDict()
        self.dst_visitor = SubstDstVisitor()
        self.reset_visitor = ResetVisitor()

        self.done = False

        self.last_cond = []
        self.last_kwargs = {}
        self.last_if_statement = None
        self.elif_cond = None
        self.next_kwargs = {}

        if not nohook:
            self.m.add_hook(self.make_always)

    #-------------------------------------------------------------------------
    def add(self, *statement, **kwargs):
        """ Adding a new assignment. This method is usually called via __call__(). """
        kwargs.update(self.next_kwargs)
        self.last_kwargs = kwargs
        self._clear_next_kwargs()

        # if there is no attributes, Elif object is reused.
        has_args = not (len(kwargs) == 0 or  # has no args
                        (len(kwargs) == 1 and 'cond' in kwargs))  # has only 'cond'

        if self.elif_cond is not None and not has_args:
            next_call = self.last_if_statement.Elif(self.elif_cond)
            next_call(*statement)
            self.last_if_statement = next_call
            self._add_dst_var(statement)
            self._clear_elif_cond()
            return self

        self._clear_last_if_statement()
        return self._add_statement(statement, **kwargs)

    #-------------------------------------------------------------------------
    def Prev(self, var, delay, initval=0, cond=None):
        """ returns a value with the specified delay """
        if not isinstance(delay, int):
            raise TypeError('delay must be int, not %s' % str(type(delay)))

        if delay <= 0:
            return var

        width = var.bit_length()

        if not isinstance(var, vtypes._Variable):
            width = self.m.TmpLocalparam(width)
            w = self.m.TmpWire(width)
            w.assign(var)
            var = w

        name_prefix = '_' + var.name
        key = '_'.join([name_prefix, str(delay)])
        if key in self.prev_dict:
            return self.prev_dict[key]

        p = var
        for i in range(delay):
            cond = make_condition(cond)
            if cond is not None:
                tmp = self.m.TmpReg(width, initval=initval)
                self._add_statement([tmp(p)], cond=cond)
                p = tmp

            else:
                tmp_name = '_'.join([name_prefix, str(i + 1)])
                if tmp_name in self.prev_dict:
                    p = self.prev_dict[tmp_name]
                    continue
                tmp = self.m.Reg(tmp_name, width, initval=initval)
                self.prev_dict[tmp_name] = tmp
                self._add_statement([tmp(p)])
                p = tmp

        return p

    #-------------------------------------------------------------------------
    def If(self, *cond):
        self._clear_elif_cond()

        cond = make_condition(*cond)

        if cond is None:
            return self

        if 'cond' not in self.next_kwargs:
            self.next_kwargs['cond'] = cond
        else:
            self.next_kwargs['cond'] = vtypes.Ands(
                self.next_kwargs['cond'], cond)

        self.last_cond = [self.next_kwargs['cond']]

        return self

    def Else(self, *statement):
        self._clear_elif_cond()

        if len(self.last_cond) == 0:
            raise ValueError("No previous condition for Else.")

        old = self.last_cond.pop()
        self.last_cond.append(vtypes.Not(old))

        # if the true-statement has delay attributes,
        # Else statement is separated.
        if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0:
            prev_cond = self.last_cond
            ret = self.Then()(*statement)
            self.last_cond = prev_cond
            return ret

        # if there is additional attribute, Else statement is separated.
        has_args = not (len(self.next_kwargs) == 0 or  # has no args
                        (len(self.next_kwargs) == 1 and 'cond' in kwargs))  # has only 'cond'
        if has_args:
            prev_cond = self.last_cond
            ret = self.Then()(*statement)
            self.last_cond = prev_cond
            return ret

        if not isinstance(self.last_if_statement, vtypes.If):
            raise ValueError("Last if-statement is not If")

        self.last_if_statement.Else(*statement)
        self._add_dst_var(statement)

        return self

    def Elif(self, *cond):
        if len(self.last_cond) == 0:
            raise ValueError("No previous condition for Else.")

        cond = make_condition(*cond)

        old = self.last_cond.pop()
        self.last_cond.append(vtypes.Not(old))
        self.last_cond.append(cond)

        # if the true-statement has delay attributes, Else statement is
        # separated.
        if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0:
            prev_cond = self.last_cond
            ret = self.Then()
            self.last_cond = prev_cond
            return ret

        if not isinstance(self.last_if_statement, vtypes.If):
            raise ValueError("Last if-statement is not If")

        self.elif_cond = cond

        cond = self._make_cond(self.last_cond)
        self.next_kwargs['cond'] = cond

        return self

    def Delay(self, delay):
        self.next_kwargs['delay'] = delay
        return self

    def Keep(self, keep):
        self.next_kwargs['keep'] = keep
        return self

    def Then(self):
        cond = self._make_cond(self.last_cond)
        self._clear_last_cond()
        self.If(cond)
        return self

    def LazyCond(self, value=True):
        self.next_kwargs['lazy_cond'] = value
        return self

    def EagerVal(self, value=True):
        self.next_kwargs['eager_val'] = value
        return self

    def Clear(self):
        self._clear_next_kwargs()
        self._clear_last_if_statement()
        self._clear_last_cond()
        self._clear_elif_cond()
        return self

    #-------------------------------------------------------------------------
    @property
    def current_delay(self):
        if 'delay' in self.next_kwargs:
            return self.next_kwargs['delay']
        return 0

    @property
    def last_delay(self):
        if 'delay' in self.last_kwargs:
            return self.last_kwargs['delay']
        return 0

    @property
    def current_condition(self):
        cond = self.next_kwargs['cond'] if 'cond' in self.next_kwargs else None
        return cond

    @property
    def last_condition(self):
        cond = self._make_cond(self.last_cond)
        return cond

    @property
    def then(self):
        return self.last_condition

    #-------------------------------------------------------------------------
    def update(self, src):

        if not isinstance(src, Seq):
            raise TypeError("src must be Seq object, not '%s'" %
                            str(type(src)))

        if self.done:
            raise ValueError("Destination Seq is already synthesized.")

        if src.done:
            return

        if id(self) == id(src):
            return

        if id(self.m) != id(src.m):
            raise ValueError("Two Seq objects have a different module.")
        if id(self.clk) != id(src.clk):
            raise ValueError("Two Seq objects have a different clock.")
        if id(self.rst) != id(src.rst):
            raise ValueError("Two Seq objects have a different reset.")

        if self.name == src.name:
            raise ValueError("Two Seq objects have a same name.")

        for delay, body in sorted(src.delayed_body.items(), key=lambda x: x[0]):
            self.delayed_body[delay].extend(body)

        self.prev_dict.update(src.prev_dict)
        self.body.extend(src.body)
        self.dst_var.update(src.dst_var)

        # Invalidated source Seq
        src.done = True

    #-------------------------------------------------------------------------
    def make_always(self, reset=(), body=()):
        if self.done:
            #raise ValueError('make_always() has been already called.')
            return

        self.done = True

        part_reset = list(reset) + list(self.make_reset())
        part_body = list(body) + list(self.make_code())

        if not part_reset and not part_body:
            pass
        elif not part_reset or self.rst is None:
            self.m.Always(vtypes.Posedge(self.clk))(
                part_body,
            )
        else:
            self.m.Always(vtypes.Posedge(self.clk))(
                vtypes.If(self.rst)(
                    part_reset,
                )(
                    part_body,
                ))

    #-------------------------------------------------------------------------
    def make_code(self):
        ret = []

        for delay, body in sorted(self.delayed_body.items(), key=lambda x: x[0],
                                  reverse=True):
            ret.extend(body)

        ret.extend(self.body)
        return ret

    #-------------------------------------------------------------------------
    def make_reset(self):
        ret = []
        for dst in self.dst_var.values():
            v = self.reset_visitor.visit(dst)
            if v is not None:
                ret.append(v)
        return ret

    #-------------------------------------------------------------------------
    def _add_statement(self, statement, keep=None, delay=None, cond=None,
                       lazy_cond=False, eager_val=False, no_delay_cond=False):

        cond = make_condition(cond)

        if keep is not None:
            for i in range(keep):
                new_delay = i if delay is None else delay + i
                self._add_statement(statement,
                                    keep=None, delay=new_delay, cond=cond,
                                    lazy_cond=lazy_cond, eager_val=eager_val,
                                    no_delay_cond=no_delay_cond)
            return self

        if delay is not None and delay > 0:
            if eager_val:
                statement = [self._add_delayed_subst(s, delay)
                             for s in statement]

            if not no_delay_cond:
                if cond is None:
                    cond = 1

                if not lazy_cond:
                    cond = self._add_delayed_cond(cond, delay)

                else:  # lazy condition
                    t = self._add_delayed_cond(1, delay)
                    if isinstance(cond, int) and cond == 1:
                        cond = t
                    else:
                        cond = vtypes.Ands(t, cond)

                statement = [vtypes.If(cond)(*statement)]

            self.delayed_body[delay].extend(statement)
            self._add_dst_var(statement)

            return self

        if cond is not None:
            statement = [vtypes.If(cond)(*statement)]
            self.last_if_statement = statement[0]

        self.body.extend(statement)
        self._add_dst_var(statement)

        return self

    #-------------------------------------------------------------------------
    def _add_dst_var(self, statement):
        for s in statement:
            values = self.dst_visitor.visit(s)
            for v in values:
                k = str(v)
                if k not in self.dst_var:
                    self.dst_var[k] = v

    #-------------------------------------------------------------------------
    def _add_delayed_cond(self, statement, delay):
        name_prefix = '_'.join(['', self.name, 'cond', str(self.tmp_count)])
        self.tmp_count += 1
        prev = statement
        for i in range(delay):
            tmp_name = '_'.join([name_prefix, str(i + 1)])
            tmp = self.m.Reg(tmp_name, initval=0)
            self._add_statement([tmp(prev)], delay=i, no_delay_cond=True)
            prev = tmp
        return prev

    #-------------------------------------------------------------------------
    def _add_delayed_subst(self, subst, delay):
        if not isinstance(subst, vtypes.Subst):
            return subst
        left = subst.left
        right = subst.right
        if isinstance(right, (bool, int, float, str,
                              vtypes._Constant, vtypes._ParameterVariable)):
            return subst
        width = left.bit_length()
        prev = right

        name_prefix = ('_'.join(['', left.name, str(self.tmp_count)])
                       if isinstance(left, vtypes._Variable) else
                       '_'.join(['', self.name, 'sbst', str(self.tmp_count)]))
        self.tmp_count += 1

        for i in range(delay):
            tmp_name = '_'.join([name_prefix, str(i + 1)])
            tmp = self.m.Reg(tmp_name, width, initval=0)
            self._add_statement([tmp(prev)], delay=i, no_delay_cond=True)
            prev = tmp
        return left(prev)

    #-------------------------------------------------------------------------
    def _clear_next_kwargs(self):
        self.next_kwargs = {}

    def _clear_last_if_statement(self):
        self.last_if_statement = None

    def _clear_last_cond(self):
        self.last_cond = []

    def _clear_elif_cond(self):
        self.elif_cond = None

    def _make_cond(self, condlist):
        ret = None
        for cond in condlist:
            if ret is None:
                ret = cond
            else:
                ret = vtypes.Ands(ret, cond)
        return ret

    #-------------------------------------------------------------------------
    def __call__(self, *statement, **kwargs):
        return self.add(*statement, **kwargs)
Ejemplo n.º 6
0
class Seq(vtypes.VeriloggenNode):
    """ Sequential Logic Manager """

    def __init__(self, m, name, clk, rst=None, nohook=False, as_module=False):
        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst

        self.tmp_count = 0
        self.delay_amount = 0
        self.delayed_body = collections.defaultdict(list)
        self.prev_dict = collections.OrderedDict()
        self.body = []

        self.dst_var = collections.OrderedDict()
        self.dst_visitor = SubstDstVisitor()
        self.reset_visitor = ResetVisitor()

        self.done = False

        self.last_cond = []
        self.last_kwargs = {}
        self.last_if_statement = None
        self.elif_cond = None
        self.next_kwargs = {}

        self.as_module = as_module

        if not nohook:
            self.m.add_hook(self.implement)

    # -------------------------------------------------------------------------
    def add(self, *statement, **kwargs):
        """ Adding a new assignment. This method is usually called via __call__(). """
        kwargs.update(self.next_kwargs)
        self.last_kwargs = kwargs
        self._clear_next_kwargs()

        # if there is no attributes, Elif object is reused.
        has_args = not (len(kwargs) == 0 or  # has no args
                        (len(kwargs) == 1 and 'cond' in kwargs))  # has only 'cond'

        if self.elif_cond is not None and not has_args:
            next_call = self.last_if_statement.Elif(self.elif_cond)
            next_call(*statement)
            self.last_if_statement = next_call
            self._add_dst_var(statement)
            self._clear_elif_cond()
            return self

        self._clear_last_if_statement()
        return self._add_statement(statement, **kwargs)

    # -------------------------------------------------------------------------
    def add_reset(self, v):
        k = str(v)
        if k not in self.dst_var:
            self.dst_var[k] = v

    # -------------------------------------------------------------------------
    def Prev(self, var, delay, initval=0, cond=None, prefix=None):
        """ returns a value with the specified delay """
        if not isinstance(delay, int):
            raise TypeError('delay must be int, not %s' % str(type(delay)))

        if delay <= 0:
            return var

        if prefix is None:
            prefix = '_'

        width = var.bit_length()
        signed = vtypes.get_signed(var)

        if not isinstance(var, vtypes._Variable):
            width = self.m.TmpLocalparam(width)
            w = self.m.TmpWire(width, signed=signed)
            w.assign(var)
            var = w

        name_prefix = prefix + var.name
        key = '_'.join([name_prefix, str(delay)])
        if key in self.prev_dict:
            return self.prev_dict[key]

        p = var
        for i in range(delay):
            cond = make_condition(cond)
            if cond is not None:
                tmp = self.m.TmpReg(
                    var, width=width, initval=initval, signed=signed)
                self._add_statement([tmp(p)], cond=cond)
                p = tmp

            else:
                tmp_name = '_'.join([name_prefix, str(i + 1)])
                if tmp_name in self.prev_dict:
                    p = self.prev_dict[tmp_name]
                    continue
                tmp = self.m.Reg(
                    tmp_name, width, initval=initval, signed=signed)
                self.prev_dict[tmp_name] = tmp
                self._add_statement([tmp(p)])
                p = tmp

        return p

    # -------------------------------------------------------------------------
    def If(self, *cond):
        self._clear_elif_cond()

        cond = make_condition(*cond)

        if cond is None:
            return self

        if 'cond' not in self.next_kwargs:
            self.next_kwargs['cond'] = cond
        else:
            self.next_kwargs['cond'] = vtypes.Ands(
                self.next_kwargs['cond'], cond)

        self.last_cond = [self.next_kwargs['cond']]

        return self

    def Else(self, *statement):
        self._clear_elif_cond()

        if len(self.last_cond) == 0:
            raise ValueError("No previous condition for Else.")

        old = self.last_cond.pop()
        self.last_cond.append(vtypes.Not(old))

        # if the true-statement has delay attributes,
        # Else statement is separated.
        if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0:
            prev_cond = self.last_cond
            ret = self.Then()(*statement)
            self.last_cond = prev_cond
            return ret

        # if there is additional attribute, Else statement is separated.
        has_args = not (len(self.next_kwargs) == 0 or  # has no args
                        (len(self.next_kwargs) == 1 and 'cond' in self.next_kwargs))  # has only 'cond'
        if has_args:
            prev_cond = self.last_cond
            ret = self.Then()(*statement)
            self.last_cond = prev_cond
            return ret

        if not isinstance(self.last_if_statement, vtypes.If):
            raise ValueError("Last if-statement is not If")

        self.last_if_statement.Else(*statement)
        self._add_dst_var(statement)

        return self

    def Elif(self, *cond):
        if len(self.last_cond) == 0:
            raise ValueError("No previous condition for Else.")

        cond = make_condition(*cond)

        old = self.last_cond.pop()
        self.last_cond.append(vtypes.Not(old))
        self.last_cond.append(cond)

        # if the true-statement has delay attributes, Else statement is
        # separated.
        if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0:
            prev_cond = self.last_cond
            ret = self.Then()
            self.last_cond = prev_cond
            return ret

        if not isinstance(self.last_if_statement, vtypes.If):
            raise ValueError("Last if-statement is not If")

        self.elif_cond = cond

        cond = self._make_cond(self.last_cond)
        self.next_kwargs['cond'] = cond

        return self

    def Delay(self, delay):
        self.next_kwargs['delay'] = delay
        return self

    def Keep(self, keep):
        self.next_kwargs['keep'] = keep
        return self

    def Then(self):
        cond = self._make_cond(self.last_cond)
        self._clear_last_cond()
        self.If(cond)
        return self

    def LazyCond(self, value=True):
        self.next_kwargs['lazy_cond'] = value
        return self

    def EagerVal(self, value=True):
        self.next_kwargs['eager_val'] = value
        return self

    def Clear(self):
        self._clear_next_kwargs()
        self._clear_last_if_statement()
        self._clear_last_cond()
        self._clear_elif_cond()
        return self

    # -------------------------------------------------------------------------
    @property
    def current_delay(self):
        if 'delay' in self.next_kwargs:
            return self.next_kwargs['delay']
        return 0

    @property
    def last_delay(self):
        if 'delay' in self.last_kwargs:
            return self.last_kwargs['delay']
        return 0

    @property
    def current_condition(self):
        cond = self.next_kwargs['cond'] if 'cond' in self.next_kwargs else None
        return cond

    @property
    def last_condition(self):
        cond = self._make_cond(self.last_cond)
        return cond

    @property
    def then(self):
        return self.last_condition

    # -------------------------------------------------------------------------
    def update(self, src):

        if not isinstance(src, Seq):
            raise TypeError("src must be Seq object, not '%s'" %
                            str(type(src)))

        if self.done:
            raise ValueError("Destination Seq is already synthesized.")

        if src.done:
            return

        if id(self) == id(src):
            return

        if id(self.m) != id(src.m):
            raise ValueError("Two Seq objects have a different module.")
        if id(self.clk) != id(src.clk):
            raise ValueError("Two Seq objects have a different clock.")
        if id(self.rst) != id(src.rst):
            raise ValueError("Two Seq objects have a different reset.")

        if self.name == src.name:
            raise ValueError("Two Seq objects have a same name.")

        for delay, body in sorted(src.delayed_body.items(), key=lambda x: x[0]):
            self.delayed_body[delay].extend(body)

        self.prev_dict.update(src.prev_dict)
        self.body.extend(src.body)
        self.dst_var.update(src.dst_var)

        # Invalidated source Seq
        src.done = True

    # -------------------------------------------------------------------------
    def implement(self):
        if self.as_module:
            self.make_module()
            return

        self.make_always()

    # -------------------------------------------------------------------------
    def make_always(self, reset=(), body=()):
        if self.done:
            #raise ValueError('make_always() has been already called.')
            return

        self.done = True

        part_reset = list(reset) + list(self.make_reset())
        part_body = list(body) + list(self.make_code())

        if not part_reset and not part_body:
            pass
        elif not part_reset or self.rst is None:
            self.m.Always(vtypes.Posedge(self.clk))(
                part_body,
            )
        else:
            self.m.Always(vtypes.Posedge(self.clk))(
                vtypes.If(self.rst)(
                    part_reset,
                )(
                    part_body,
                ))

    # -------------------------------------------------------------------------
    def make_module(self, reset=(), body=()):
        if self.done:
            #raise ValueError('make_always() has been already called.')
            return

        self.done = True

        m = Module(self.name)

        clk = m.Input('CLK')

        if self.rst is not None:
            rst = m.Input('RST')
        else:
            rst = None

        body = list(body) + list(self.make_code())
        dsts = self.dst_var.values()
        src_visitor = SubstSrcVisitor()

        # collect sources in destination variable definitions
        for dst in dsts:
            if isinstance(dst, (vtypes.Pointer, vtypes.Slice, vtypes.Cat)):
                raise ValueError(
                    'Partial assignment is not supported by as_module mode.')

            if isinstance(dst, vtypes._Variable):
                if dst.width is not None:
                    src_visitor.visit(dst.width)
                if dst.length is not None:
                    src_visitor.visit(dst.length)

        # collect sources in statements
        for statement in body:
            src_visitor.visit(statement)

        srcs = src_visitor.srcs.values()

        # collect sources in source variable definitions
        for src in srcs:
            if isinstance(src, vtypes._Variable):
                if src.width is not None:
                    src_visitor.visit(src.width)
                if src.length is not None:
                    src_visitor.visit(src.length)

        srcs = src_visitor.srcs.values()

        params = collections.OrderedDict()
        ports = collections.OrderedDict()
        src_rename_dict = collections.OrderedDict()

        # create parameter/localparam definitions
        for src in srcs:
            if isinstance(src, (vtypes.Parameter, vtypes.Localparam)):
                arg_name = src.name
                v = m.Parameter(arg_name, src.value, src.width, src.signed)
                src_rename_dict[src.name] = v
                params[arg_name] = src

        src_rename_visitor = SrcRenameVisitor(src_rename_dict)

        for src in srcs:
            if isinstance(src, (vtypes.Parameter, vtypes.Localparam)):
                continue

            arg_name = 'i_%s' % src.name

            if src.length is not None:
                width = src.bit_length()
                length = src.length
                pack_width = vtypes.Mul(width, length)
                out_line = self.m.TmpWire(
                    pack_width, prefix='_%s_%s' % (self.name, src.name))
                i = self.m.TmpGenvar(prefix='i')
                v = out_line[i * width:(i + 1) * width]
                g = self.m.GenerateFor(i(0), i < length, i(i + 1))
                p = g.Assign(v(src[i]))

                rep_width = (src_rename_visitor.visit(src.width)
                             if src.width is not None else None)
                rep_length = src_rename_visitor.visit(src.length)
                pack_width = (rep_length if rep_width is None else
                              vtypes.Mul(rep_length, rep_width))
                in_line = m.Input(arg_name + '_line', pack_width,
                                  signed=src.get_signed())
                in_array = m.Wire(arg_name, rep_width, rep_length,
                                  signed=src.get_signed())
                i = m.TmpGenvar(prefix='i')
                v = in_line[i * rep_width:(i + 1) * rep_width]
                g = m.GenerateFor(i(0), i < rep_length, i(i + 1))
                p = g.Assign(in_array[i](v))

                src_rename_dict[src.name] = in_array
                ports[in_line.name] = out_line

            else:
                rep_width = (src_rename_visitor.visit(src.width)
                             if src.width is not None else None)
                v = m.Input(arg_name, rep_width, signed=src.get_signed())

                src_rename_dict[src.name] = v
                ports[arg_name] = src

        for dst in dsts:
            arg_name = dst.name

            rep_width = (src_rename_visitor.visit(dst.width)
                         if dst.width is not None else None)
            out = m.OutputReg(arg_name, rep_width, signed=dst.get_signed())
            out_wire = self.m.TmpWire(rep_width, signed=dst.get_signed(),
                                      prefix='_%s_%s' % (self.name, arg_name))
            self.m.Always()(dst(out_wire, blk=True))
            ports[arg_name] = out_wire

        body = [src_rename_visitor.visit(statement)
                for statement in body]

        reset = list(reset) + list(self.make_reset())

        if not reset and not body:
            pass
        elif not reset or rst is None:
            m.Always(vtypes.Posedge(clk))(
                body,
            )
        else:
            m.Always(vtypes.Posedge(clk))(
                vtypes.If(rst)(
                    reset,
                )(
                    body,
                ))

        arg_params = [(name, param) for name, param in params.items()]

        arg_ports = [('CLK', self.clk)]
        if self.rst is not None:
            arg_ports.append(('RST', self.rst))

        arg_ports.extend([(name, port) for name, port in ports.items()])

        sub = Submodule(self.m, m, 'inst_' + m.name, '_%s_' % self.name,
                        arg_params=arg_params, arg_ports=arg_ports)

    # -------------------------------------------------------------------------
    def make_code(self):
        ret = []

        for delay, body in sorted(self.delayed_body.items(), key=lambda x: x[0],
                                  reverse=True):
            ret.extend(body)

        ret.extend(self.body)
        return ret

    # -------------------------------------------------------------------------
    def make_reset(self):
        ret = []
        for dst in self.dst_var.values():
            v = self.reset_visitor.visit(dst)
            if v is not None:
                ret.append(v)
        return ret

    # -------------------------------------------------------------------------
    def _add_statement(self, statement, keep=None, delay=None, cond=None,
                       lazy_cond=False, eager_val=False, no_delay_cond=False):

        cond = make_condition(cond)

        if keep is not None:
            for i in range(keep):
                new_delay = i if delay is None else delay + i
                self._add_statement(statement,
                                    keep=None, delay=new_delay, cond=cond,
                                    lazy_cond=lazy_cond, eager_val=eager_val,
                                    no_delay_cond=no_delay_cond)
            return self

        if delay is not None and delay > 0:
            if eager_val:
                statement = [self._add_delayed_subst(s, delay)
                             for s in statement]

            if not no_delay_cond:
                if cond is None:
                    cond = 1

                if not lazy_cond:
                    cond = self._add_delayed_cond(cond, delay)

                else:  # lazy condition
                    t = self._add_delayed_cond(1, delay)
                    if isinstance(cond, int) and cond == 1:
                        cond = t
                    else:
                        cond = vtypes.Ands(t, cond)

                statement = [vtypes.If(cond)(*statement)]

            self.delayed_body[delay].extend(statement)
            self._add_dst_var(statement)

            return self

        if cond is not None:
            statement = [vtypes.If(cond)(*statement)]
            self.last_if_statement = statement[0]

        self.body.extend(statement)
        self._add_dst_var(statement)

        return self

    # -------------------------------------------------------------------------
    def _add_dst_var(self, statement):
        for s in statement:
            values = self.dst_visitor.visit(s)
            for v in values:
                k = str(v)
                if k not in self.dst_var:
                    self.dst_var[k] = v

    # -------------------------------------------------------------------------
    def _add_delayed_cond(self, statement, delay):
        name_prefix = '_'.join(['', self.name, 'cond', str(self.tmp_count)])
        self.tmp_count += 1
        prev = statement
        for i in range(delay):
            tmp_name = '_'.join([name_prefix, str(i + 1)])
            tmp = self.m.Reg(tmp_name, initval=0)
            self._add_statement([tmp(prev)], delay=i, no_delay_cond=True)
            prev = tmp
        return prev

    # -------------------------------------------------------------------------
    def _add_delayed_subst(self, subst, delay):
        if not isinstance(subst, vtypes.Subst):
            return subst
        left = subst.left
        right = subst.right
        if isinstance(right, (bool, int, float, str,
                              vtypes._Constant, vtypes._ParameterVariable)):
            return subst
        width = left.bit_length()
        signed = vtypes.get_signed(left)
        prev = right

        name_prefix = ('_'.join(['', left.name, str(self.tmp_count)])
                       if isinstance(left, vtypes._Variable) else
                       '_'.join(['', self.name, 'sbst', str(self.tmp_count)]))
        self.tmp_count += 1

        for i in range(delay):
            tmp_name = '_'.join([name_prefix, str(i + 1)])
            tmp = self.m.Reg(tmp_name, width, initval=0, signed=signed)
            self._add_statement([tmp(prev)], delay=i, no_delay_cond=True)
            prev = tmp
        return left(prev)

    # -------------------------------------------------------------------------
    def _clear_next_kwargs(self):
        self.next_kwargs = {}

    def _clear_last_if_statement(self):
        self.last_if_statement = None

    def _clear_last_cond(self):
        self.last_cond = []

    def _clear_elif_cond(self):
        self.elif_cond = None

    def _make_cond(self, condlist):
        ret = None
        for cond in condlist:
            if ret is None:
                ret = cond
            else:
                ret = vtypes.Ands(ret, cond)
        return ret

    # -------------------------------------------------------------------------
    def __call__(self, *statement, **kwargs):
        return self.add(*statement, **kwargs)
Ejemplo n.º 7
0
class FSM(vtypes.VeriloggenNode):
    """ Finite State Machine Generator """

    def __init__(self, m, name, clk, rst, width=32, initname='init',
                 nohook=False, as_module=False):
        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst
        self.width = width
        self.state_count = 0
        self.state = self.m.Reg(name, width)  # set initval later

        self.mark = collections.OrderedDict()  # key:index
        self._set_mark(0, self.name + '_' + initname)
        self.state.initval = self._get_mark(0)

        self.body = collections.defaultdict(list)
        self.jump = collections.defaultdict(list)

        self.delay_amount = 0
        self.delayed_state = collections.OrderedDict()  # key:delay
        self.delayed_body = collections.defaultdict(
            functools.partial(collections.defaultdict, list))  # key:delay
        self.delayed_cond = collections.OrderedDict()  # key:name
        self.tmp_count = 0

        self.dst_var = collections.OrderedDict()
        self.dst_visitor = SubstDstVisitor()
        self.reset_visitor = ResetVisitor()

        self.seq = Seq(self.m, self.name + '_par', clk, rst, nohook=True)

        self.done = False

        self.last_cond = []
        self.last_kwargs = {}
        self.last_if_statement = None
        self.elif_cond = None
        self.next_kwargs = {}

        self.as_module = as_module

        if not nohook:
            self.m.add_hook(self.implement)

    # -------------------------------------------------------------------------
    def goto(self, dst, cond=None, else_dst=None):
        if cond is None and 'cond' in self.next_kwargs:
            cond = self.next_kwargs['cond']
        self._clear_next_kwargs()
        self._clear_last_if_statement()
        self._clear_last_cond()

        src = self.current
        return self._go(src, dst, cond, else_dst)

    def goto_init(self, cond=None):
        if cond is None and 'cond' in self.next_kwargs:
            cond = self.next_kwargs['cond']
        self._clear_next_kwargs()
        self._clear_last_if_statement()
        self._clear_last_cond()

        src = self.current
        dst = 0
        return self._go(src, dst, cond)

    def goto_next(self, cond=None):
        if cond is None and 'cond' in self.next_kwargs:
            cond = self.next_kwargs['cond']
        self._clear_next_kwargs()
        self._clear_last_if_statement()
        self._clear_last_cond()

        src = self.current
        dst = self.current + 1
        ret = self._go(src, dst, cond=cond)
        self.inc()
        return ret

    def goto_from(self, src, dst, cond=None, else_dst=None):
        if cond is None and 'cond' in self.next_kwargs:
            cond = self.next_kwargs['cond']
        self._clear_next_kwargs()
        self._clear_last_if_statement()
        self._clear_last_cond()

        return self._go(src, dst, cond, else_dst)

    def inc(self):
        self._set_index(None)

    # -------------------------------------------------------------------------
    def add(self, *statement, **kwargs):
        """ add new assignments """
        kwargs.update(self.next_kwargs)
        self.last_kwargs = kwargs
        self._clear_next_kwargs()

        # if there is no attributes, Elif object is reused.
        has_args = not (len(kwargs) == 0 or  # has no args
                        (len(kwargs) == 1 and 'cond' in kwargs))  # has only 'cond'

        if self.elif_cond is not None and not has_args:
            next_call = self.last_if_statement.Elif(self.elif_cond)
            next_call(*statement)
            self.last_if_statement = next_call
            self._add_dst_var(statement)
            self._clear_elif_cond()
            return self

        self._clear_last_if_statement()
        return self._add_statement(statement, **kwargs)

    # -------------------------------------------------------------------------
    def add_reset(self, v):
        return self.seq.add_reset(v)

    # -------------------------------------------------------------------------
    def Prev(self, var, delay, initval=0, cond=None, prefix=None):
        return self.seq.Prev(var, delay, initval, cond, prefix)

    # -------------------------------------------------------------------------
    def If(self, *cond):
        self._clear_elif_cond()

        cond = make_condition(*cond)

        if cond is None:
            return self

        if 'cond' not in self.next_kwargs:
            self.next_kwargs['cond'] = cond
        else:
            self.next_kwargs['cond'] = vtypes.Ands(
                self.next_kwargs['cond'], cond)

        self.last_cond = [self.next_kwargs['cond']]

        return self

    def Else(self, *statement, **kwargs):
        self._clear_elif_cond()

        if len(self.last_cond) == 0:
            raise ValueError("No previous condition for Else.")

        old = self.last_cond.pop()
        self.last_cond.append(vtypes.Not(old))

        # if the true-statement has delay attributes,
        # Else statement is separated.
        if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0:
            prev_cond = self.last_cond
            ret = self.Then()(*statement)
            self.last_cond = prev_cond
            return ret

        # if there is additional attribute, Else statement is separated.
        has_args = not (len(self.next_kwargs) == 0 or  # has no args
                        (len(self.next_kwargs) == 1 and 'cond' in kwargs))  # has only 'cond'

        if has_args:
            prev_cond = self.last_cond
            ret = self.Then()(*statement)
            self.last_cond = prev_cond
            return ret

        if not isinstance(self.last_if_statement, vtypes.If):
            raise ValueError("Last if-statement is not If")

        self.last_if_statement.Else(*statement)
        self._add_dst_var(statement)

        return self

    def Elif(self, *cond):
        if len(self.last_cond) == 0:
            raise ValueError("No previous condition for Else.")

        cond = make_condition(*cond)

        old = self.last_cond.pop()
        self.last_cond.append(vtypes.Not(old))
        self.last_cond.append(cond)

        # if the true-statement has delay attributes, Else statement is
        # separated.
        if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0:
            prev_cond = self.last_cond
            ret = self.Then()
            self.last_cond = prev_cond
            return ret

        if not isinstance(self.last_if_statement, vtypes.If):
            raise ValueError("Last if-statement is not If")

        self.elif_cond = cond

        cond = self._make_cond(self.last_cond)
        self.next_kwargs['cond'] = cond

        return self

    def Delay(self, delay):
        self.next_kwargs['delay'] = delay
        return self

    def Keep(self, keep):
        self.next_kwargs['keep'] = keep
        return self

    def Then(self):
        cond = self._make_cond(self.last_cond)
        self._clear_last_cond()
        self.If(cond)
        return self

    def LazyCond(self, value=True):
        self.next_kwargs['lazy_cond'] = value
        return self

    def EagerVal(self, value=True):
        self.next_kwargs['eager_val'] = value
        return self

    def Clear(self):
        self._clear_next_kwargs()
        self._clear_last_if_statement()
        self._clear_last_cond()
        self._clear_elif_cond()
        return self

    # -------------------------------------------------------------------------
    @property
    def current(self):
        return self.state_count

    @property
    def next(self):
        return self.current + 1

    @property
    def current_delay(self):
        if 'delay' in self.next_kwargs:
            return self.next_kwargs['delay']
        return 0

    @property
    def last_delay(self):
        if 'delay' in self.last_kwargs:
            return self.last_kwargs['delay']
        return 0

    @property
    def current_condition(self):
        cond = self.next_kwargs['cond'] if 'cond' in self.next_kwargs else None
        if cond is not None:
            cond = vtypes.AndList(self.state == self.state_count, cond)
        else:
            cond = self.state == self.state_count
        return cond

    @property
    def last_condition(self):
        cond = self._make_cond(self.last_cond)
        if cond is not None:
            cond = vtypes.AndList(self.state == self.state_count, cond)
        else:
            cond = self.state == self.state_count
        return cond

    @property
    def then(self):
        return self.last_condition

    @property
    def here(self):
        return self.state == self.current

    # -------------------------------------------------------------------------
    def implement(self):
        if self.as_module:
            self.make_module()
            return

        self.make_always()

    # -------------------------------------------------------------------------
    def make_always(self, reset=(), body=(), case=True):
        if self.done:
            #raise ValueError('make_always() has been already called.')
            return

        self.done = True

        part_reset = self.make_reset(reset)
        part_body = list(body) + list(self.make_case()
                                      if case else self.make_if())
        self.m.Always(vtypes.Posedge(self.clk))(
            vtypes.If(self.rst)(
                part_reset,
            )(
                part_body,
            ))

    # -------------------------------------------------------------------------
    def make_module(self, reset=(), body=(), case=True):
        if self.done:
            #raise ValueError('make_always() has been already called.')
            return

        self.done = True

        m = Module('sub_%s' % self.name)

        clk = m.Input('CLK')

        if self.rst is not None:
            rst = m.Input('RST')
        else:
            rst = None

        body = list(body) + list(self.make_case()
                                 if case else self.make_if())
        dst_var = self.seq.dst_var
        dst_var.update(self.dst_var)
        dsts = dst_var.values()
        src_visitor = SubstSrcVisitor()

        # collect sources in destination variable definitions
        for dst in dsts:
            if isinstance(dst, (vtypes.Pointer, vtypes.Slice, vtypes.Cat)):
                raise ValueError(
                    'Partial assignment is not supported by as_module mode.')

            if isinstance(dst, vtypes._Variable):
                if dst.width is not None:
                    src_visitor.visit(dst.width)
                if dst.length is not None:
                    src_visitor.visit(dst.length)

        # collect sources in statements
        for statement in body:
            src_visitor.visit(statement)

        srcs = src_visitor.srcs.values()

        # collect sources in source variable definitions
        for src in srcs:
            if isinstance(src, vtypes._Variable):
                if src.width is not None:
                    src_visitor.visit(src.width)
                if src.length is not None:
                    src_visitor.visit(src.length)

        srcs = src_visitor.srcs.values()

        params = collections.OrderedDict()
        ports = collections.OrderedDict()
        src_rename_dict = collections.OrderedDict()

        fsm_orig_labels = [v.name for v in self.mark.values()]
        fsm_labels = collections.OrderedDict()

        # create parameter/localparam definitions
        for src in srcs:
            if isinstance(src, (vtypes.Parameter, vtypes.Localparam)):
                if src.name in fsm_orig_labels:
                    fsm_labels[src.name] = m.Localparam(src.name, src.value)
                    continue

                arg_name = src.name
                v = m.Parameter(arg_name, src.value, src.width, src.signed)
                src_rename_dict[src.name] = v
                params[arg_name] = src

        src_rename_visitor = SrcRenameVisitor(src_rename_dict)

        state_width = src_rename_visitor.visit(self.state.width)
        state_initval = src_rename_visitor.visit(self.state.initval)
        state = m.OutputReg(self.state.name, state_width,
                            initval=state_initval)
        out_state = self.m.TmpWire(state_width,
                                   prefix='_%s_out' % self.state.name)
        self.m.Always()(self.state(out_state, blk=True))
        ports[state.name] = out_state

        src_rename_dict[self.state.name] = state

        for delay, s in sorted(self.delayed_state.items(), key=lambda x: x[0]):
            s_width = src_rename_visitor.visit(s.width)
            s_initval = src_rename_visitor.visit(s.initval)
            d = m.OutputReg(s.name, s_width, initval=s_initval)
            out_d = self.m.TmpWire(s_width, prefix='_%s_out' % d.name)
            self.m.Always()(s(out_d, blk=True))
            ports[s.name] = out_d

        state_names = [self.state.name]
        state_names.extend([s.name for s in self.delayed_state.values()])

        for src in srcs:
            if isinstance(src, (vtypes.Parameter, vtypes.Localparam)):
                continue

            if src.name in state_names:
                continue

            if src.name in list(self.delayed_cond.keys()):
                rep_width = (src_rename_visitor.visit(src.width)
                             if src.width is not None else None)
                v = m.Reg(src.name, rep_width, initval=0)
                src_rename_dict[src.name] = v
                continue

            arg_name = 'i_%s' % src.name

            if src.length is not None:
                width = src.bit_length()
                length = src.length
                pack_width = vtypes.Mul(width, length)
                out_line = self.m.TmpWire(pack_width, prefix='_%s' % self.name)
                i = self.m.TmpGenvar(prefix='i')
                v = out_line[i * width:(i + 1) * width]
                g = self.m.GenerateFor(i(0), i < length, i(i + 1))
                p = g.Assign(v(src[i]))

                rep_width = (src_rename_visitor.visit(src.width)
                             if src.width is not None else None)
                rep_length = src_rename_visitor.visit(src.length)
                pack_width = (rep_length if rep_width is None else
                              vtypes.Mul(rep_length, rep_width))
                in_line = m.Input(arg_name + '_line', pack_width,
                                  signed=src.get_signed())
                in_array = m.Wire(arg_name, rep_width, rep_length,
                                  signed=src.get_signed())
                i = m.TmpGenvar(prefix='i')
                v = in_line[i * rep_width:(i + 1) * rep_width]
                g = m.GenerateFor(i(0), i < rep_length, i(i + 1))
                p = g.Assign(in_array[i](v))

                src_rename_dict[src.name] = in_array
                ports[in_line.name] = out_line

            else:
                rep_width = (src_rename_visitor.visit(src.width)
                             if src.width is not None else None)
                v = m.Input(arg_name, rep_width, signed=src.get_signed())

                src_rename_dict[src.name] = v
                ports[arg_name] = src

        for dst in dsts:
            if dst.name in list(self.delayed_cond.keys()):
                continue

            arg_name = dst.name

            rep_width = (src_rename_visitor.visit(dst.width)
                         if dst.width is not None else None)
            out = m.OutputReg(arg_name, rep_width, signed=dst.get_signed())
            out_wire = self.m.TmpWire(rep_width, signed=dst.get_signed(),
                                      prefix='_%s_%s' % (self.name, arg_name))
            self.m.Always()(dst(out_wire, blk=True))
            ports[arg_name] = out_wire

        body = [src_rename_visitor.visit(statement)
                for statement in body]

        reset = self.make_reset(reset)

        if not reset and not body:
            pass
        elif not reset or rst is None:
            m.Always(vtypes.Posedge(clk))(
                body,
            )
        else:
            m.Always(vtypes.Posedge(clk))(
                vtypes.If(rst)(
                    reset,
                )(
                    body,
                ))

        arg_params = [(name, param) for name, param in params.items()]

        arg_ports = [('CLK', self.clk)]
        if self.rst is not None:
            arg_ports.append(('RST', self.rst))

        arg_ports.extend([(name, port) for name, port in ports.items()])

        sub = Submodule(self.m, m, 'inst_' + m.name, '_%s_' % self.name,
                        arg_params=arg_params, arg_ports=arg_ports)

    # -------------------------------------------------------------------------
    def make_case(self):
        indexes = set(self.body.keys())
        indexes.update(set(self.jump.keys()))

        for index in indexes:
            self._add_mark(index)

        ret = []
        ret.extend(self.seq.make_code())
        ret.extend(self._get_delayed_substs())

        for delay, dct in sorted(self.delayed_body.items(),
                                 key=lambda x: x[0], reverse=True):
            body = tuple([self._get_delayed_when_statement(index, delay)
                          for index in sorted(dct.keys(), key=lambda x:x)])
            case = vtypes.Case(self._get_delayed_state(delay))(*body)
            ret.append(case)

        body = tuple([self._get_when_statement(index)
                      for index in sorted(indexes, key=lambda x:x)])
        case = vtypes.Case(self.state)(*body)

        if len(case.statement) > 0:
            ret.append(case)

        return ret

    def make_if(self):
        indexes = set(self.body.keys())
        indexes.update(set(self.jump.keys()))

        for index in indexes:
            self._add_mark(index)

        ret = []
        ret.extend(self.seq.make_code())
        ret.extend(self._get_delayed_substs())

        for delay, dct in sorted(self.delayed_body.items(),
                                 key=lambda x: x[0], reverse=True):
            ret.append([self._get_delayed_if_statement(index, delay)
                        for index in sorted(dct.keys(), key=lambda x:x)])

        ret.extend([self._get_if_statement(index)
                    for index in sorted(indexes, key=lambda x:x)])
        return ret

    # -------------------------------------------------------------------------
    def make_reset(self, reset):
        ret = collections.OrderedDict()

        for v in reset:
            if not isinstance(v, vtypes.Subst):
                raise TypeError(
                    'make_reset requires Subst, not %s' % str(type(v)))
            key = str(v.left)
            if key not in ret:
                ret[key] = v

        v = self.reset_visitor.visit(self.state)
        key = str(self.state)
        if v is not None and key not in ret:
            ret[key] = v

        for dst in self.delayed_state.values():
            v = self.reset_visitor.visit(dst)
            if v is None:
                continue
            key = str(v.left)
            if key not in ret:
                ret[key] = v

        for dst in self.dst_var.values():
            v = self.reset_visitor.visit(dst)
            if v is None:
                continue
            key = str(v.left)
            if key not in ret:
                ret[key] = v

        for v in self.seq.make_reset():
            if not isinstance(v, vtypes.Subst):
                raise TypeError(
                    'make_reset requires Subst, not %s' % str(type(v)))
            key = str(v.left)
            if key not in ret:
                ret[key] = v

        return list(ret.values())

    # -------------------------------------------------------------------------
    def set_index(self, index):
        return self._set_index(index)

    # -------------------------------------------------------------------------
    def _go(self, src, dst, cond=None, else_dst=None):
        self._add_jump(src, dst, cond, else_dst)
        return self

    def _add_jump(self, src, dst, cond=None, else_dst=None):
        self.jump[src].append((dst, cond, else_dst))

    # -------------------------------------------------------------------------
    def _add_statement(self, statement, index=None, keep=None, delay=None, cond=None,
                       lazy_cond=False, eager_val=False, no_delay_cond=False):

        cond = make_condition(cond)
        index = self._to_index(index) if index is not None else self.current

        if keep is not None:
            for i in range(keep):
                new_delay = i if delay is None else delay + i
                self._add_statement(statement, index=index,
                                    keep=None, delay=new_delay, cond=cond,
                                    lazy_cond=lazy_cond, eager_val=eager_val,
                                    no_delay_cond=no_delay_cond)
            return self

        if delay is not None and delay > 0:
            self._add_delayed_state(delay)

            if eager_val:
                statement = [self._add_delayed_subst(s, index, delay)
                             for s in statement]

            if not no_delay_cond:
                if cond is None:
                    cond = 1

                if not lazy_cond:
                    cond = self._add_delayed_cond(cond, index, delay)

                else:  # lazy condition
                    t = self._add_delayed_cond(1, index, delay)
                    if isinstance(cond, int) and cond == 1:
                        cond = t
                    else:
                        cond = vtypes.Ands(t, cond)

                statement = [vtypes.If(cond)(*statement)]

            self.delayed_body[delay][index].extend(statement)
            self._add_dst_var(statement)

            return self

        if cond is not None:
            statement = [vtypes.If(cond)(*statement)]
            self.last_if_statement = statement[0]

        self.body[index].extend(statement)
        self._add_dst_var(statement)

        return self

    # -------------------------------------------------------------------------
    def _add_dst_var(self, statement):
        for s in statement:
            values = self.dst_visitor.visit(s)
            for v in values:
                k = str(v)
                if k not in self.dst_var:
                    self.dst_var[k] = v

    # -------------------------------------------------------------------------
    def _add_delayed_cond(self, statement, index, delay):
        name_prefix = '_'.join(
            ['', self.name, 'cond', str(index), str(self.tmp_count)])
        self.tmp_count += 1
        prev = statement
        for i in range(delay):
            tmp_name = '_'.join([name_prefix, str(i + 1)])
            tmp = self.m.Reg(tmp_name, initval=0)
            self.delayed_cond[tmp_name] = tmp
            self._add_statement([tmp(prev)], delay=i, no_delay_cond=True)
            prev = tmp
        return prev

    # -------------------------------------------------------------------------
    def _add_delayed_subst(self, subst, index, delay):
        if not isinstance(subst, vtypes.Subst):
            return subst
        left = subst.left
        right = subst.right
        if isinstance(right, (bool, int, float, str,
                              vtypes._Constant, vtypes._ParameterVariable)):
            return subst
        width = left.bit_length()
        signed = vtypes.get_signed(left)
        prev = right

        name_prefix = ('_'.join(['', left.name, str(index), str(self.tmp_count)])
                       if isinstance(left, vtypes._Variable) else
                       '_'.join(['', self.name, 'sbst', str(index), str(self.tmp_count)]))
        self.tmp_count += 1

        for i in range(delay):
            tmp_name = '_'.join([name_prefix, str(i + 1)])
            tmp = self.m.Reg(tmp_name, width, initval=0, signed=signed)
            self._add_statement([tmp(prev)], delay=i, no_delay_cond=True)
            prev = tmp
        return left(prev)

    # -------------------------------------------------------------------------
    def _clear_next_kwargs(self):
        self.next_kwargs = {}

    def _clear_last_if_statement(self):
        self.last_if_statement = None

    def _clear_last_cond(self):
        self.last_cond = []

    def _clear_elif_cond(self):
        self.elif_cond = None

    def _make_cond(self, condlist):
        ret = None
        for cond in condlist:
            if ret is None:
                ret = cond
            else:
                ret = vtypes.Ands(ret, cond)
        return ret

    # -------------------------------------------------------------------------
    def _set_index(self, index=None):
        if index is None:
            self.state_count += 1
            return self.state_count
        self.state_count = index
        return self.state_count

    def _get_mark(self, index=None):
        if index is None:
            index = self.state_count
        if index not in self.mark:
            raise KeyError("No such index in FSM marks: %s" % index)
        return self.mark[index]

    def _set_mark(self, index=None, name=None):
        if index is None:
            index = self.state_count
        if name is None:
            name = self.name + '_' + str(index)
        self.mark[index] = self.m.Localparam(name, index)

    def _get_mark_index(self, s):
        for index, m in self.mark.items():
            if m.name == s.name:
                return index
        raise KeyError("No such mark in FSM marks: %s" % s.name)

    # -------------------------------------------------------------------------
    def _add_mark(self, index):
        index = self._to_index(index)
        if index not in self.mark:
            self._set_mark(index)
        mark = self._get_mark(index)
        return mark

    def _to_index(self, index):
        if not isinstance(index, int):
            index = self._get_mark_index(index)
        return index

    # -------------------------------------------------------------------------
    def _add_delayed_state(self, value):
        if not isinstance(value, int):
            raise TypeError("Delay amount must be int, not '%s'" %
                            str(type(value)))

        if value < 0:
            raise ValueError("Delay amount must be positive number")

        if value == 0:
            return self.state

        if value <= self.delay_amount:
            return self._get_delayed_state(value)

        for i in range(self.delay_amount + 1, value + 1):
            d = self.m.Reg(''.join(['_d', str(i), '_', self.name]), self.width,
                           initval=self._get_mark(0))
            self.delayed_state[i] = d

        self.delay_amount = value
        return d

    def _get_delayed_state(self, value):
        if value == 0:
            return self.state
        if value not in self.delayed_state:
            raise IndexError('No such index %d in delayed state' % value)
        return self.delayed_state[value]

    def _get_delayed_substs(self):
        ret = []
        prev = self.state
        for d in range(1, self.delay_amount + 1):
            ret.append(vtypes.Subst(self.delayed_state[d], prev))
            prev = self.delayed_state[d]
        return ret

    def _init_delayed_state(self):
        ret = []
        for d in range(1, self.delay_amount + 1):
            ret.append(vtypes.Subst(self.delayed_state[d], self._get_mark(0)))
        return ret

    def _to_state_assign(self, dst, cond=None, else_dst=None):
        dst_mark = self._get_mark(dst)
        value = self.state(dst_mark)
        if cond is not None:
            value = vtypes.If(cond)(value)
            if else_dst is not None:
                else_dst_mark = self._get_mark(else_dst)
                value = value.Else(self.state(else_dst_mark))
        return value

    # -------------------------------------------------------------------------
    def _cond_case(self, index):
        if index not in self.mark:
            self._set_mark(index)
        return self._get_mark(index)

    def _cond_if(self, index):
        if index not in self.mark:
            self._set_mark(index)
        return (self.state == self._get_mark(index))

    def _delayed_cond_if(self, index, delay):
        if index not in self.mark:
            self._set_mark(index)
        if delay > 0 and delay not in self.delayed_state:
            self._add_delayed_state(delay)
        return (self._get_delayed_state(delay) == self._get_mark(index))

    def _get_when_statement(self, index):
        body = []
        body.extend(self.body[index])
        for dst, cond, else_dst in self.jump[index]:
            self._add_mark(dst)
            if else_dst is not None:
                self._add_mark(else_dst)
            body.append(self._to_state_assign(dst, cond, else_dst))
        return vtypes.When(self._cond_case(index))(*body)

    def _get_delayed_when_statement(self, index, delay):
        return vtypes.When(self._cond_case(index))(*self.delayed_body[delay][index])

    def _get_if_statement(self, index):
        body = []
        body.extend(self.body[index])
        for dst, cond, else_dst in self.jump[index]:
            self._add_mark(dst)
            if else_dst is not None:
                self._add_mark(else_dst)
            body.append(self._to_state_assign(dst, cond, else_dst))
        return vtypes.If(self._cond_if(index))(*body)

    def _get_delayed_if_statement(self, index, delay):
        return vtypes.If(self._delayed_cond_if(index, delay))(*self.delayed_body[delay][index])

    # -------------------------------------------------------------------------
    def __call__(self, *statement, **kwargs):
        return self.add(*statement, **kwargs)

    def __getitem__(self, index):
        return self.body[index]

    def __len__(self):
        return self.state_count + 1