OpenCores
URL https://opencores.org/ocsvn/nocmodel/nocmodel/trunk

Subversion Repositories nocmodel

[/] [nocmodel/] [trunk/] [nocmodel/] [noc_base.py] - Diff between revs 2 and 4

Only display areas with differences | Details | Blame | View Log

Rev 2 Rev 4
#!/usr/bin/env python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
 
 
#
#
# NoC Base Objects
# NoC Base Objects
#
#
# Author:  Oscar Diaz
# Author:  Oscar Diaz
# Version: 0.1
# Version: 0.2
# Date:    03-03-2011
# Date:    05-07-2012
 
 
#
#
# This code is free software; you can redistribute it and/or
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# version 2.1 of the License, or (at your option) any later version.
#
#
# This code is distributed in the hope that it will be useful,
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
# Lesser General Public License for more details.
#
#
# You should have received a copy of the GNU Lesser General Public
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# License along with this library; if not, write to the
# Free Software  Foundation, Inc., 59 Temple Place, Suite 330,
# Free Software  Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA  02111-1307  USA
# Boston, MA  02111-1307  USA
#
#
 
 
#
#
# Changelog:
# Changelog:
#
#
# 03-03-2011 : (OD) initial release
# 03-03-2011 : (OD) initial release
 
# 05-07-2012 : (OD) intercon class, major changes, various bugfixes
#
#
 
 
"""
"""
================
=====================
NoCmodel Base Objects
NoCmodel Base Objects
================
=====================
 
 
This module declares classes used on a Network-on-chip representation:
This module declares classes used on a Network-on-chip representation:
 
 
* NoC container class
* NoC container class
    * Router base class
    * Router base class
    * Channel base class
    * Channel base class
    * IPCore base class
    * IPCore base class
 
    * Intercon base class
    * Protocol base class
    * Protocol base class
    * Packet class
    * Packet class
"""
"""
 
 
import networkx as nx
import networkx as nx
 
from myhdl import Signal, SignalType, intbv, bin
 
from collections import OrderedDict
 
from math import ceil as mathceil
 
 
class noc(nx.Graph):
class noc(nx.Graph):
    """
    """
    Base class for NoC modeling.
    Base class for NoC modeling.
    Based on a Graph object that hold the NoC structure
    Based on a Graph object that hold the NoC structure
 
 
    Arguments
    Arguments
    * kwargs: optional parameters to put as object attributes
    * kwargs: optional parameters to put as object attributes
    """
    """
    def __init__(self, **kwargs):
    def __init__(self, **kwargs):
        """
        """
        NoCmodel constructor
        NoCmodel constructor
        """
        """
        nx.Graph.__init__(self, **kwargs)
        nx.Graph.__init__(self, **kwargs)
 
        if not hasattr(self, "name"):
 
            self.name = ""
 
        if not hasattr(self, "description"):
 
            self.description = ""
 
 
 
    def __repr__(self):
 
        if self.name != "":
 
            return "<%s '%s'>" % (self.__class__.__name__, self.name)
 
        else:
 
            return "<%s at '%d'>" % (self.__class__.__name__, id(self))
 
 
    # objects management functions
    # objects management functions
    def add_router(self, name="", with_ipcore=False, **kwargs):
    def add_router(self, name="", with_ipcore=False, **kwargs):
        """
        """
        Create a base router object and add it to NoC model.
        Create a base router object and add it to NoC model.
 
 
        Arguments
        Arguments
        * name: optional name for this router. By default has the form of
        * name: optional name for this router. By default has the form of
          "R_<index>"
          "R_<index>"
        * with_ipcore: If True, add an ipcore to the created router.
        * with_ipcore: If True, add an ipcore to the created router.
        * kwargs: optional parameters to put as object attributes
        * kwargs: optional parameters to put as object attributes
 
 
        Return: reference to the created router object
        Return: reference to the created router object
        """
        """
        #nodeidx = self._get_next_nodeidx()
        #nodeidx = self._get_next_nodeidx()
        routernode = router(index=None, name=name, graph_ref=self, **kwargs)
        routernode = router(index=None, name=name, graph_ref=self, **kwargs)
        retval = self.add_router_from_object(routernode)
        retval = self.add_router_from_object(routernode)
        if name == "":
        if name == "":
            retval.name = "R_%d" % retval.index
            retval.name = "R_%d" % retval.index
        if with_ipcore:
        if with_ipcore:
            # kwargs are reserved for router creation, not for ipcore.
            # kwargs are reserved for router creation, not for ipcore.
            self.add_ipcore(retval)
            self.add_ipcore(retval)
        return retval
        return retval
 
 
    def add_router_from_object(self, router_ref):
    def add_router_from_object(self, router_ref):
        """
        """
        Add an existing router object to NoC model.
        Add an existing router object to NoC model.
 
 
        Use this function to add an object based on a derived class of
        Use this function to add an object based on a derived class of
        base router defined in this module.
        base router defined in this module.
 
 
        Arguments
        Arguments
        * router_ref: reference to the router object
        * router_ref: reference to the router object
 
 
        Return: the same reference passed in router_ref
        Return: the same reference passed in router_ref
 
 
        Notes:
        Notes:
        * This function will change router_ref.index and router_ref.graph_ref
        * This function will change router_ref.index and router_ref.graph_ref
          attributes when inserted in the NoC model.
          attributes when inserted in the NoC model.
        """
        """
        if not isinstance(router_ref, router):
        if not isinstance(router_ref, router):
            raise ValueError("Argument 'router_ref' is not a router object.")
            raise ValueError("Argument 'router_ref' is not a router object.")
 
 
        router_ref.index = self._get_next_nodeidx()
        router_ref.index = self._get_next_nodeidx()
        router_ref.graph_ref = self
        router_ref.graph_ref = self
        # don't forget that index is used for address
        # don't forget that index is used for address
        router_ref.address = router_ref.index
        router_ref.address = router_ref.index
        self.add_node(router_ref.index, router_ref=router_ref)
        self.add_node(router_ref.index, router_ref=router_ref)
        return router_ref
        return router_ref
 
 
    def add_channel(self, router1, router2, name="", **kwargs):
    def add_channel(self, router1, router2, name="", **kwargs):
        """
        """
        Create a base channel object to link two objects and add it
        Create a base channel object to link two objects and add it
        to NoC model.
        to NoC model.
 
 
        Arguments:
        Arguments:
        * router1: reference to a router, router index or ipcore
        * router1: reference to a router, router index or ipcore
        * router2: -idem-
        * router2: -idem-
        * name: optional argument for channel name
        * name: optional argument for channel name
        * kwargs: optional parameters to put as object attributes
        * kwargs: optional parameters to put as object attributes
 
 
        Notes:
        Notes:
        * If router1 or router2 is an ipcore reference, this method creates
        * If router1 or router2 is an ipcore reference, this method creates
          the special channel object and update ipcore references. Additionally,
          the special channel object and update ipcore references. Additionally,
          if both arguments are ipcores, throw an error exception
          if both arguments are ipcores, throw an error exception
        """
        """
        if isinstance(router1, ipcore) and isinstance(router2, ipcore):
        if isinstance(router1, ipcore) and isinstance(router2, ipcore):
            raise ValueError("Both object references cannot be ipcore objects.")
            raise ValueError("Both object references cannot be ipcore objects.")
 
 
        rhash = [None, None]
        rhash = [None, None]
        rrefs = [None, None]
        rrefs = [None, None]
        for targetid, routertarget in enumerate((router1, router2)):
        for targetid, routertarget in enumerate((router1, router2)):
            if isinstance(routertarget, router):
            if isinstance(routertarget, router):
                if routertarget.index in self.node:
                if routertarget.index in self.node:
                    rhash[targetid] = routertarget.index
                    rhash[targetid] = routertarget.index
                    rrefs[targetid] = self.node[routertarget.index]["router_ref"]
                    rrefs[targetid] = self.node[routertarget.index]["router_ref"]
            elif isinstance(routertarget, ipcore):
            elif isinstance(routertarget, ipcore):
                # special channel
                # special channel
                rhash[targetid] = None
                rhash[targetid] = None
                rrefs[targetid] = routertarget
                rrefs[targetid] = routertarget
            elif isinstance(routertarget, int):
            elif isinstance(routertarget, int):
                if routertarget in self.node:
                if routertarget in self.node:
                    rhash[targetid] = routertarget
                    rhash[targetid] = routertarget
                    rrefs[targetid] = self.node[routertarget]["router_ref"]
                    rrefs[targetid] = self.node[routertarget]["router_ref"]
 
 
        if rrefs[0] is None:
        if rrefs[0] is None:
            raise ValueError("Object not found for argument 'router1'")
            raise ValueError("Object not found for argument 'router1'")
        if rrefs[1] is None:
        if rrefs[1] is None:
            raise ValueError("Object not found for argument 'router2'")
            raise ValueError("Object not found for argument 'router2'")
 
 
        if None in rhash:
        if None in rhash:
            ipcore_idx = rhash.index(None)
            ipcore_idx = rhash.index(None)
            # ipcore channel
            # ipcore channel
            if name == "":
            if name == "":
                # channel default name format 
                # channel default name format 
                name = "CH_IP_%s" % rrefs[ipcore_idx].name
                name = "CH_IP_%s" % rrefs[ipcore_idx].name
            channelnode = channel(index=None, name=name, graph_ref=self, **kwargs)
            channelnode = channel(index=None, name=name, graph_ref=self, **kwargs)
        else:
        else:
            # inter-routers channel
            # inter-routers channel
            if name == "":
            if name == "":
                # channel default name format 
                # channel default name format 
                name = "CH_%s:%s" % (rrefs[0].name, rrefs[1].name)
                name = "CH_%s:%s" % (rrefs[0].name, rrefs[1].name)
            channelnode = channel(index=self._get_next_edgeidx(), name=name, graph_ref=self, **kwargs)
            channelnode = channel(index=self._get_next_edgeidx(), name=name, graph_ref=self, **kwargs)
            self.add_edge(rhash[0], rhash[1], channel_ref = channelnode)
            self.add_edge(rhash[0], rhash[1], channel_ref = channelnode)
        channelnode.endpoints = rrefs
        channelnode.endpoints = rrefs
        return channelnode
        return channelnode
 
 
    def add_from_channel(self, channel_ref, router1=None, router2=None):
    def add_from_channel(self, channel_ref, router1=None, router2=None):
        """
        """
        Add a channel object to NoC model.
        Add a channel object to NoC model.
 
 
        Use this function to add an object based on a derived class of
        Use this function to add an object based on a derived class of
        base channel defined in this module.
        base channel defined in this module.
 
 
        Arguments
        Arguments
        * channel_ref: reference to the channel object
        * channel_ref: reference to the channel object
        * router1: optional reference to a router, router index or ipcore
        * router1: optional reference to a router, router index or ipcore
        * router2: -idem-
        * router2: -idem-
 
 
        Return: the same reference passed in channel_ref
        Return: the same reference passed in channel_ref
 
 
        Notes:
        Notes:
        * If router1 or router2 are not used as arguments, will assume that
        * If router1 or router2 are not used as arguments, will assume that
          channel object has defined its attribute "endpoints" with the
          channel object has defined its attribute "endpoints" with the
          objects to connect. If the objects don't exist in the NoC model,
          objects to connect. If the objects don't exist in the NoC model,
          throw an error exception.
          throw an error exception.
 
 
        * If router1 or router2 is an ipcore reference, this method creates
        * If router1 or router2 is an ipcore reference, this method creates
          the special channel object and update ipcore references. Additionally,
          the special channel object and update ipcore references. Additionally,
          if both arguments are ipcores, throw an error exception.
          if both arguments are ipcores, throw an error exception.
 
 
        * This function will change channel_ref.index and channel_ref.graph_ref
        * This function will change channel_ref.index and channel_ref.graph_ref
          attributes when inserted in the NoC model. Also it may change
          attributes when inserted in the NoC model. Also it may change
          channel_ref.endpoints with router1 and router2 references.
          channel_ref.endpoints with router1 and router2 references.
        """
        """
        if not isinstance(channel_ref, channel):
        if not isinstance(channel_ref, channel):
            raise ValueError("Argument 'channel_ref' is not a channel object.")
            raise ValueError("Argument 'channel_ref' is not a channel object.")
 
 
        if isinstance(router1, ipcore) and isinstance(router2, ipcore):
        if isinstance(router1, ipcore) and isinstance(router2, ipcore):
            raise ValueError("Both object references cannot be ipcore objects.")
            raise ValueError("Both object references cannot be ipcore objects.")
 
 
        rhash = [None, None]
        rhash = [None, None]
        rrefs = [None, None]
        rrefs = [None, None]
        for targetid, routertarget in enumerate((router1, router2)):
        for targetid, routertarget in enumerate((router1, router2)):
            if isinstance(routertarget, router):
            if isinstance(routertarget, router):
                if routertarget.index in self.node:
                if routertarget.index in self.node:
                    rhash[targetid] = routertarget.index
                    rhash[targetid] = routertarget.index
                    rrefs[targetid] = self.node[routertarget.index]["router_ref"]
                    rrefs[targetid] = self.node[routertarget.index]["router_ref"]
            elif isinstance(routertarget, ipcore):
            elif isinstance(routertarget, ipcore):
                # special channel
                # special channel
                rhash[targetid] = None
                rhash[targetid] = None
                rrefs[targetid] = routertarget
                rrefs[targetid] = routertarget
            elif isinstance(routertarget, int):
            elif isinstance(routertarget, int):
                if routertarget in self.node:
                if routertarget in self.node:
                    rhash[targetid] = routertarget
                    rhash[targetid] = routertarget
                    rrefs[targetid] = self.node[routertarget]["router_ref"]
                    rrefs[targetid] = self.node[routertarget]["router_ref"]
 
 
        if (router1 is None) and (router2 is None):
        if (router1 is None) and (router2 is None):
            # extract from endpoints attribute
            # extract from endpoints attribute
            if not hasattr(channel_ref, "endpoints"):
            if not hasattr(channel_ref, "endpoints"):
                raise ValueError("Channel object has not attribute 'endpoints'")
                raise ValueError("Channel object has not attribute 'endpoints'")
            for i in range(2):
            for i in range(2):
                if not isinstance(channel_ref.endpoints[i], [router, ipcore]):
                if not isinstance(channel_ref.endpoints[i], [router, ipcore]):
                    raise ValueError("Channel object: attribute 'endpoints'[%d] is not a router or an ipcore" % i)
                    raise ValueError("Channel object: attribute 'endpoints'[%d] is not a router or an ipcore" % i)
                if isinstance(channel_ref.endpoints[i], router):
                if isinstance(channel_ref.endpoints[i], router):
                    if channel_ref.endpoints[i].index in self.node:
                    if channel_ref.endpoints[i].index in self.node:
                        rhash[i] = channel_ref.endpoints[i].index
                        rhash[i] = channel_ref.endpoints[i].index
                        rrefs[i] = channel_ref.endpoints[i]
                        rrefs[i] = channel_ref.endpoints[i]
                if isinstance(channel_ref.endpoints[i], ipcore):
                if isinstance(channel_ref.endpoints[i], ipcore):
                    rhash[i] = None
                    rhash[i] = None
                    rrefs[i] = channel_ref.endpoints[i]
                    rrefs[i] = channel_ref.endpoints[i]
 
 
        if rrefs[0] is None:
        if rrefs[0] is None:
            raise ValueError("Object not found for argument 'router1'")
            raise ValueError("Object not found for argument 'router1'")
        if rrefs[1] is None:
        if rrefs[1] is None:
            raise ValueError("Object not found for argument 'router2'")
            raise ValueError("Object not found for argument 'router2'")
 
 
        if None in rhash:
        if None in rhash:
            ipcore_idx = rhash.index(None)
            ipcore_idx = rhash.index(None)
            channel_ref.index = None
            channel_ref.index = None
            # ipcore channel: adjust the references
            # ipcore channel: adjust the references
            rrefs[ipcore_idx].channel_ref = channel_ref
            rrefs[ipcore_idx].channel_ref = channel_ref
            # the other reference must be a router object
            # the other reference must be a router object
            rrefs[ipcore_idx - 1].ipcore_ref = rrefs[ipcore_idx]
            rrefs[ipcore_idx - 1].ipcore_ref = rrefs[ipcore_idx]
        else:
        else:
            # inter-routers channel
            # inter-routers channel
            channel_ref.index = self._get_next_edgeidx()
            channel_ref.index = self._get_next_edgeidx()
            self.add_edge(rhash[0], rhash[1], channel_ref=channel_ref)
            self.add_edge(rhash[0], rhash[1], channel_ref=channel_ref)
        # update common references
        # update common references
        channel_ref.graph_ref = self
        channel_ref.graph_ref = self
        channel_ref.endpoints = rrefs
        channel_ref.endpoints = rrefs
        return channel_ref
        return channel_ref
 
 
 
 
    def add_ipcore(self, router_ref, name="", **kwargs):
    def add_ipcore(self, router_ref, name="", **kwargs):
        """
        """
        Create an ipcore object and connect it to the router reference argument
        Create an ipcore object and connect it to the router reference argument
 
 
        Arguments
        Arguments
        * router_ref: reference to an existing router
        * router_ref: reference to an existing router
        * name: optional name for this router. By default has the form of
        * name: optional name for this router. By default has the form of
          "IP_<router_index>"
          "IP_<router_index>"
        * kwargs: optional parameters to put as object attributes
        * kwargs: optional parameters to put as object attributes
 
 
        Return: reference to the created ipcore object
        Return: reference to the created ipcore object
 
 
        Notes:
        Notes:
        * This function automatically adds a special channel object
        * This function automatically adds a special channel object
          (router-to-ipcore) and adjust its relations in all involved objects.
          (router-to-ipcore) and adjust its relations in all involved objects.
        """
        """
        if router_ref not in self.router_list():
        if router_ref not in self.router_list():
            raise ValueError("Argument 'router_ref' must be an existing router.")
            raise ValueError("Argument 'router_ref' must be an existing router.")
        if name == "":
        if name == "":
            # channel default name format 
            # channel default name format 
            name = "IP_%d" % router_ref.index
            name = "IP_%d" % router_ref.index
        # fix channel name, based on ipcore name
        # fix channel name, based on ipcore name
        chname = "CH_%s" % name
        chname = "CH_%s" % name
        newip = ipcore(name=name, router_ref=router_ref, graph_ref=self, **kwargs)
        newip = ipcore(name=name, router_ref=router_ref, graph_ref=self, **kwargs)
        channelnode = channel(index=None, name=chname, graph_ref=self, endpoints=[router_ref, newip])
        channelnode = channel(index=None, name=chname, graph_ref=self, endpoints=[router_ref, newip])
        # fix references
        # fix references
        newip.channel_ref = channelnode
        newip.channel_ref = channelnode
        router_ref.ipcore_ref = newip
        router_ref.ipcore_ref = newip
        return newip
        return newip
 
 
    def add_from_ipcore(self, ipcore_ref, router_ref, channel_ref=None):
    def add_from_ipcore(self, ipcore_ref, router_ref, channel_ref=None):
        """
        """
        Add a ipcore object to NoC model.
        Add a ipcore object to NoC model.
 
 
        Arguments
        Arguments
        * ipcore_ref: reference to ipcore object
        * ipcore_ref: reference to ipcore object
        * router_ref: reference to an existing router to connect
        * router_ref: reference to an existing router to connect
        * channel_ref: optional channel object that connect the router and
        * channel_ref: optional channel object that connect the router and
          the ipcore. If not used, this function will create a new channel object.
          the ipcore. If not used, this function will create a new channel object.
 
 
        Return: the same reference passed in ipcore_ref
        Return: the same reference passed in ipcore_ref
 
 
        Notes:
        Notes:
        * This function automatically adds a special channel object
        * This function automatically adds a special channel object
          (router-to-ipcore) and adjust its relations in all involved objects.
          (router-to-ipcore) and adjust its relations in all involved objects.
        """
        """
        if not isinstance(ipcore_ref, ipcore):
        if not isinstance(ipcore_ref, ipcore):
            raise ValueError("Argument 'ipcore_ref' is not an ipcore object.")
            raise ValueError("Argument 'ipcore_ref' is not an ipcore object.")
        if router_ref not in self.router_list():
        if router_ref not in self.router_list():
            raise ValueError("Argument 'router_ref' must be an existing router.")
            raise ValueError("Argument 'router_ref' must be an existing router.")
 
 
        if channel_ref != None:
        if channel_ref != None:
            if not isinstance(channel_ref, channel):
            if not isinstance(channel_ref, channel):
                raise ValueError("Argument 'channel_ref' is not a channel object.")
                raise ValueError("Argument 'channel_ref' is not a channel object.")
            else:
            else:
                channel_ref.index = None
                channel_ref.index = None
                channel_ref.graph_ref = self
                channel_ref.graph_ref = self
                channel_ref.endpoints = [router_ref, ipcore_ref]
                channel_ref.endpoints = [router_ref, ipcore_ref]
        else:
        else:
            # channel default name format 
            # channel default name format 
            chname = "CH_IP_%d" % router_ref.index
            chname = "CH_IP_%d" % router_ref.index
            channel_ref = channel(index=None, name=chname, graph_ref=self, endpoints=[router_ref, ipcore_ref])
            channel_ref = channel(index=None, name=chname, graph_ref=self, endpoints=[router_ref, ipcore_ref])
 
 
        # fix references
        # fix references
        ipcore_ref.router_ref = router_ref
        ipcore_ref.router_ref = router_ref
        ipcore_ref.channel_ref = channel_ref
        ipcore_ref.channel_ref = channel_ref
        ipcore_ref.graph_ref = self
        ipcore_ref.graph_ref = self
        router_ref.ipcore_ref = ipcore_ref
        router_ref.ipcore_ref = ipcore_ref
 
 
        return ipcore_ref
        return ipcore_ref
 
 
    def del_router(self, router_ref):
    def del_router(self, router_ref):
        """
        """
        Remove router_ref from the NoC model
        Remove router_ref from the NoC model
 
 
        TODO: not implemented
        TODO: not implemented
        """
        """
        pass
        pass
 
 
    def del_channel(self, channel_ref):
    def del_channel(self, channel_ref):
        """
        """
        Remove channel_ref from the NoC model
        Remove channel_ref from the NoC model
 
 
        TODO: not implemented
        TODO: not implemented
        """
        """
        pass
        pass
 
 
    def del_ipcore(self, ipcore_ref):
    def del_ipcore(self, ipcore_ref):
        """
        """
        Remove ipcore_ref from the NoC model
        Remove ipcore_ref from the NoC model
 
 
        TODO: not implemented
        TODO: not implemented
        """
        """
        pass
        pass
 
 
    # list generation functions
    # list generation functions
    def router_list(self):
    def router_list(self):
        l = []
        l = []
        for i in self.nodes_iter(data=True):
        for i in self.nodes_iter(data=True):
            l.append(i[1]["router_ref"])
            r = i[1].get("router_ref", None)
 
            if r is not None:
 
                l.append(r)
        return l
        return l
 
 
    def ipcore_list(self):
    def ipcore_list(self):
        l = []
        l = []
        for i in self.nodes_iter(data=True):
        for i in self.router_list():
            if i[1]["router_ref"].ipcore_ref != None:
            ip = getattr(i, "ipcore_ref", None)
                l.append(i[1]["router_ref"].ipcore_ref)
            if ip is not None:
 
                l.append(ip)
        return l
        return l
 
 
    def channel_list(self):
    def channel_list(self, with_ipcore_channel=False):
        # this function does not list ipcore channels
 
        l = []
        l = []
        for i in self.edges_iter(data=True):
        for i in self.edges_iter(data=True):
            l.append(i[2]["channel_ref"])
            ch = i[2].get("channel_ref", None)
 
            if ch is not None:
 
                l.append(ch)
 
        if with_ipcore_channel:
 
            for i in self.ipcore_list():
 
                ch = getattr(i, "channel_ref", None)
 
                if ch is not None:
 
                    l.append(ch)
        return l
        return l
 
 
    def all_list(self):
    def all_list(self, with_ipcore_channel=False):
        l = self.router_list()
        l = self.router_list()
        l.extend(self.ipcore_list())
        l.extend(self.ipcore_list())
        l.extend(self.channel_list())
        l.extend(self.channel_list(with_ipcore_channel))
        return l
        return l
 
 
    # query functions
    # query functions
    def get_router_by_address(self, address):
    def get_router_by_address(self, address):
        for r in self.router_list():
        for r in self.router_list():
            if r.address == address:
            if r.address == address:
                return r
                return r
        return False
        return False
 
 
 
    # update functions
 
    def update_nocdata(self):
 
        for r in self.router_list():
 
            r.update_ports_info()
 
            r.update_routes_info()
 
        for ch in self.channel_list(True):
 
            ch.update_ports_info()
 
 
    # hidden functions
    # hidden functions
    def _add_router_from_node(self, node, name="", router_ref=None, **kwargs):
    def _add_router_from_node(self, node, name="", router_ref=None, **kwargs):
        """
        """
        Create a router object (or use an existing router reference) based on
        Create a router object (or use an existing router reference) based on
        an existing empty node on graph object.
        an existing empty node on graph object.
        """
        """
        if router_ref is None:
        if router_ref is None:
            # index comes from node
            # index comes from node
            if name == "":
            if name == "":
                name = "R_%d" % node
                name = "R_%s" % repr(node)
            routernode = router(index=node, name=name, graph_ref=self, **kwargs)
            routernode = router(index=node, name=name, graph_ref=self, **kwargs)
        else:
        else:
            if not isinstance(router_ref, router):
            if not isinstance(router_ref, router):
                raise ValueError("Argument 'router_ref' is not a router object.")
                raise ValueError("Argument 'router_ref' is not a router object.")
            routernode = router_ref
            routernode = router_ref
            routernode.index = node
            routernode.index = node
            routernode.graph_ref = self
            routernode.graph_ref = self
        self.node[node]["router_ref"] = routernode
        self.node[node]["router_ref"] = routernode
        return routernode
        return routernode
 
 
    def _add_channel_from_edge(self, edge, name="", channel_ref=None, **kwargs):
    def _add_channel_from_edge(self, edge, name="", channel_ref=None, **kwargs):
        """
        """
        Create a channel object (or use an existing channel reference) based
        Create a channel object (or use an existing channel reference) based
        on an existing edge on graph object.
        on an existing edge on graph object.
        """
        """
        # inter-routers channels only
        # inter-routers channels only
        rrefs = [self.node[edge[0]]["router_ref"], self.node[edge[1]]["router_ref"]]
        rrefs = [self.node[edge[0]]["router_ref"], self.node[edge[1]]["router_ref"]]
        chindex = self.edges().index(edge)
        chindex = self.edges().index(edge)
        if channel_ref is None:
        if channel_ref is None:
            if name == "":
            if name == "":
                # channel default name format 
                # channel default name format 
                name = "CH_%s:%s" % (rrefs[0].name, rrefs[1].name)
                name = "CH_%s:%s" % (rrefs[0].name, rrefs[1].name)
            channelnode = channel(index=chindex, name=name, graph_ref=self, **kwargs)
            channelnode = channel(index=chindex, name=name, graph_ref=self, **kwargs)
        else:
        else:
            if not isinstance(channel_ref, channel):
            if not isinstance(channel_ref, channel):
                raise ValueError("Argument 'channel_ref' is not a channel object.")
                raise ValueError("Argument 'channel_ref' is not a channel object.")
            channelnode = channel_ref
            channelnode = channel_ref
            channelnode.index = chindex
            channelnode.index = chindex
            channelnode.graph_ref = self
            channelnode.graph_ref = self
        channelnode.endpoints = rrefs
        channelnode.endpoints = rrefs
        self.get_edge_data(edge[0], edge[1])["channel_ref"] = channelnode
        self.get_edge_data(edge[0], edge[1])["channel_ref"] = channelnode
 
 
        return channelnode
        return channelnode
 
 
    def _get_next_nodeidx(self):
    def _get_next_nodeidx(self):
        # get the next node index number
        # get the next node index number
        # don't use intermediate available indexes
        # don't use intermediate available indexes
        return len(self.nodes())
        return len(self.nodes())
 
 
    def _get_next_edgeidx(self):
    def _get_next_edgeidx(self):
        # get the next edge index number
        # get the next edge index number
        # don't use intermediate available indexes
        # don't use intermediate available indexes
        return len(self.edges())
        return len(self.edges())
 
 
# *******************************
# *******************************
# Generic models for NoC elements
# Generic models for NoC elements
# *******************************
# *******************************
 
 
class nocobject():
class nocobject():
    """
    """
    NoC base object
    NoC base object
 
 
    This base class is used to implement common methods for NoC objects.
    This base class is used to implement common methods for NoC objects.
    Don't use directly.
    Don't use directly.
    """
    """
 
    name = ""
 
    description = ""
 
 
 
    def __repr__(self):
 
        if self.name != "":
 
            return "<%s '%s'>" % (self.__class__.__name__, self.name)
 
        else:
 
            return "<%s at '%d'>" % (self.__class__.__name__, id(self))
 
 
    def get_protocol_ref(self):
    def get_protocol_ref(self):
        """
        """
        Get protocol object for this instance
        Get protocol object for this instance
        """
        """
        if hasattr(self, "protocol_ref"):
        if hasattr(self, "protocol_ref"):
            if isinstance(self.protocol_ref, protocol):
            if isinstance(self.protocol_ref, protocol):
                return self.protocol_ref
                return self.protocol_ref
        if isinstance(self.graph_ref.protocol_ref, protocol):
        if isinstance(self.graph_ref.protocol_ref, protocol):
            return self.graph_ref.protocol_ref
            return self.graph_ref.protocol_ref
        # nothing?
        # nothing?
        return None
        return None
 
 
 
    def get_address(self):
 
        """
 
        Get address related to this object. If it is a router or a ipcore,
 
        returns the address in the router. If it is a channel, return a list
 
        or pair addresses from its endpoints. If it is another object without
 
        address, return None.
 
        """
 
        if hasattr(self, "address"):
 
            return self.address
 
        else:
 
            # try ipcore
 
            if isinstance(self, ipcore):
 
                return self.router_ref.address
 
            # try channel
 
            if isinstance(self, channel):
 
                return [x.get_address() for x in self.endpoints]
 
            # nothing?
 
            return None
 
 
class ipcore(nocobject):
class ipcore(nocobject):
    """
    """
    IP core base object
    IP core base object
 
 
    This object represents a IP Core object and its properties. This base class
    This object represents a IP Core object and its properties. This base class
    is meant to either be inherited or extended by adding other attributes.
    is meant to either be inherited or extended by adding other attributes.
 
 
    Relations with other objects:
    Relations with other objects:
    * It should be related to one NoC model object (self.graph_ref)
    * It should be related to one NoC model object (self.graph_ref)
    * It should have one reference to a router object (self.router_ref), even if
    * It should have one reference to a router object (self.router_ref), even if
      the ipcore has a direct connection to the NoC.
      the ipcore has a direct connection to the NoC.
    * It should have one reference to a channel object (self.channel_ref). This
    * It should have one reference to a channel object (self.channel_ref). This
      channel exclusively link this ipcore and its router.
      channel exclusively link this ipcore and its router.
 
 
    Attributes:
    Attributes:
    * name
    * name
    * router_ref: optional reference to its related router.
    * router_ref: optional reference to its related router.
    * channel_ref: optional reference to its related channel
    * channel_ref: optional reference to its related channel
    * graph_ref: optional reference to its graph model
    * graph_ref: optional reference to its graph model
    """
    """
    def __init__(self, name, **kwargs):
    def __init__(self, name, **kwargs):
        # Basic properties
        # Basic properties
        self.name = name
        self.name = name
        # default values
        # default values
        self.router_ref = None
        self.router_ref = None
        self.channel_ref = None
        self.channel_ref = None
        self.graph_ref = None
        self.graph_ref = None
        for key in kwargs.keys():
        for key in kwargs.keys():
            setattr(self, key, kwargs[key])
            setattr(self, key, kwargs[key])
 
        # ports structure
 
        self.ports = {}
 
 
 
    # update functions: call them when the underlying NoC structure
 
    # has changed
 
    def update_ports_info(self):
 
        """
 
        Update the dictionary "ports". For an ipcore, it only has one element
 
        to its router.
 
 
 
        Ports dictionary has the following structure:
 
        * key: address of its related router
 
        * value: dictionary with the following keys:
 
            * "peer" (required): reference to its router
 
            * "channel" (required): reference to the channel that connects this
 
              ipcore and its router.
 
            * Optional keys can be added to this dictionary with the same
 
              meaning as other ports.
 
        """
 
        myaddr = self.get_address()
 
        self.ports = {myaddr: {}}
 
        self.ports[myaddr]["peer"] = self.router_ref
 
        self.ports[myaddr]["channel"] = self.channel_ref
 
 
class router(nocobject):
class router(nocobject):
    """
    """
    Router base object
    Router base object
 
 
    This object represents a router object and its properties. This base class
    This object represents a router object and its properties. This base class
    is meant to either be inherited or extended by adding other attributes.
    is meant to either be inherited or extended by adding other attributes.
 
 
    Relations with other objects:
    Relations with other objects:
    * It should be related to one NoC model object (self.graph_ref)
    * It should be related to one NoC model object (self.graph_ref)
    * It should be one of the node attributes in the graph model
    * It should be one of the node attributes in the graph model
      (node["router_ref"])
      (node["router_ref"])
    * It may have one reference to an ipcore object (self.ipcore_ref)
    * It may have one reference to an ipcore object (self.ipcore_ref)
    * It has a port list with relations to other routers through channel objects,
    * It has a port list with relations to other routers through channel objects,
      and only one relation to its ipcore object through one channel.
      and only one relation to its ipcore object through one channel.
      (self.ports). Note that this attribute must be updated after changing
      (self.ports). Note that this attribute must be updated after changing
      the NoC model.
      the NoC model.
 
 
    Attributes:
    Attributes:
    * index: index on a noc object. Essential to search for a router object
    * index: index on a noc object. Essential to search for a router object
    * name
    * name
    * ipcore_ref: optional reference to its related ipcore
    * ipcore_ref: optional reference to its related ipcore
    * graph_ref: optional reference to its graph model
    * graph_ref: optional reference to its graph model
    """
    """
    def __init__(self, index, name, **kwargs):
    def __init__(self, index, name, **kwargs):
        # Basic properties
        # Basic properties
        self.index = index
        self.index = index
        self.name = name
        self.name = name
        # default values
        # default values
        self.ipcore_ref = None
        self.ipcore_ref = None
        self.graph_ref = None
        self.graph_ref = None
        # address can be anything, but let use index by default
        # address can be anything, but let use index by default
        # note that address can be overriden with optional arguments in kwargs
        # note that address can be overriden with optional arguments in kwargs
        self.address = index
        self.address = index
        for key in kwargs.keys():
        for key in kwargs.keys():
            setattr(self, key, kwargs[key])
            setattr(self, key, kwargs[key])
        # ports structure
        # ports structure
        self.ports = {}
        self.ports = {}
        # available routes info
        # available routes info
        self.routes_info = {}
        self.routes_info = {}
 
 
    # update functions: call them when the underlying NoC structure
    # update functions: call them when the underlying NoC structure
    # has changed
    # has changed
    def update_ports_info(self):
    def update_ports_info(self):
        """
        """
        Update the dictionary "ports": information about router neighbors,
        Update the dictionary "ports": information about router neighbors,
        the channels that connect them and its references.
        the channels that connect them and its references.
 
 
        Ports dictionary has the following structure:
        Ports dictionary has the following structure:
        * key: address of the neighbor router that this port connects.
        * key: address of the neighbor router that this port connects.
        * value: dictionary with the following keys:
        * value: dictionary with the following keys:
            * "peer" (required): reference to the neighbor router
            * "peer" (required): reference to the neighbor router
            * "channel" (required): reference to the channel that connects this
            * "channel" (required): reference to the channel that connects this
              router and its neighbor router.
              router and its neighbor router.
            * Optional keys can be added to this dictionary.
            * Optional keys can be added to this dictionary.
        * Also, the special key "local address" holds the port to
        * Also, the special key "local address" holds the port to
          router's ipcore. Its values are:
          router's ipcore. Its values are:
            * "peer" (required): reference to its ipcore
            * "peer" (required): reference to its ipcore
            * "channel" (required): reference to the channel that connects this
            * "channel" (required): reference to the channel that connects this
              router and its ipcore.
              router and its ipcore.
            * Optional keys can be added to this dictionary with the same
            * Optional keys can be added to this dictionary with the same
              meaning as other ports.
              meaning as other ports.
        """
        """
        # port definitions
        # port definitions
        localhash = self.address
        localhash = self.address
        updated_addr = [self.address]
        updated_addr = [self.address]
        for neighborhash in self.graph_ref.neighbors(localhash):
        for neighborhash in self.graph_ref.neighbors(localhash):
            neighbor = self.graph_ref.node[neighborhash]["router_ref"]
            neighbor = self.graph_ref.node[neighborhash]["router_ref"]
            #check if already defined in ports dictionary
            #check if already defined in ports dictionary
            if neighbor.address not in self.ports:
            if neighbor.address not in self.ports:
                self.ports[neighbor.address] = {}
                self.ports[neighbor.address] = {}
            # update relevant data
            # update relevant data
            self.ports[neighbor.address]["peer"] = neighbor
            self.ports[neighbor.address]["peer"] = neighbor
            ch_ref = self.graph_ref.edge[localhash][neighborhash]["channel_ref"]
            ch_ref = self.graph_ref.edge[localhash][neighborhash]["channel_ref"]
            self.ports[neighbor.address]["channel"] = ch_ref
            self.ports[neighbor.address]["channel"] = ch_ref
            updated_addr.append(neighbor.address)
            updated_addr.append(neighbor.address)
 
 
        # special port: ipcore
        # special port: ipcore
        if self.address not in self.ports:
        if self.address not in self.ports:
            self.ports[self.address] = {}
            self.ports[self.address] = {}
        self.ports[self.address]["peer"] = self.ipcore_ref
        self.ports[self.address]["peer"] = self.ipcore_ref
        # take channel reference from ipcore. Other channels are related to
        # take channel reference from ipcore. Other channels are related to
        # an edge on the graph model. Channels in an ipcore are special because
        # an edge on the graph model. Channels in an ipcore are special because
        # they don't have a related edge, just link an ipcore and this router
        # they don't have a related edge, just link an ipcore and this router
        self.ports[self.address]["channel"] = self.ipcore_ref.channel_ref
        self.ports[self.address]["channel"] = self.ipcore_ref.channel_ref
 
 
        # clean 'deleted' ports
        # clean 'deleted' ports
        keys = self.ports.iterkeys()
        keys = self.ports.iterkeys()
        for deleted in keys:
        for deleted in keys:
            if deleted not in updated_addr:
            if deleted not in updated_addr:
                del self.ports[deleted]
                del self.ports[deleted]
 
 
    def update_routes_info(self):
    def update_routes_info(self):
        """
        """
        Update the dictionary "routes_info": it is a table with information
        Update the dictionary "routes_info": it is a table with information
        about how a package, starting from this router, can reach another one.
        about how a package, starting from this router, can reach another one.
 
 
        routes_info dictionary has the following structure:
        routes_info dictionary has the following structure:
        * keys : the address of all the routers in NoC
        * keys : the address of all the routers in NoC
        * values : an ordered list of dictionaries with
        * values : an ordered list of dictionaries with
            * "next" : address of the next router
            * "next" : address of the next router
            * "paths" : list of possible paths for key destination
            * "paths" : list of possible paths for key destination
 
 
        """
        """
        # this function will calculate a new table!
        # this function will calculate a new table!
        self.routes_info.clear()
        self.routes_info.clear()
 
 
        #mynodehash = (self.coord_x, self.coord_y)
        #mynodehash = (self.coord_x, self.coord_y)
        mynodehash = self.index
        mynodehash = self.index
 
 
        for destrouter in self.graph_ref.router_list():
        for destrouter in self.graph_ref.router_list():
            # discard route to myself
            # discard route to myself
            if destrouter == self:
            if destrouter == self:
                continue
                continue
            #desthash = (destrouter.coord_x, destrouter.coord_y)
            #desthash = (destrouter.coord_x, destrouter.coord_y)
            desthash = destrouter.index
            desthash = destrouter.index
 
 
            # entry for destrouter
            # entry for destrouter
            self.routes_info[destrouter.index] = []
            self.routes_info[destrouter.index] = []
 
 
            # first: take all shortest paths (function not available on NetworkX)
            # first: take all shortest paths (function not available on NetworkX)
            shortest_routes = all_shortest_paths(self.graph_ref, mynodehash, desthash)
            shortest_routes = all_shortest_paths(self.graph_ref, mynodehash, desthash)
            # convert nodehashes to router addresses
            # convert nodehashes to router addresses
            shortest_r_addr = [map(lambda x : self.graph_ref.node[x]["router_ref"].address, i) for i in shortest_routes]
            shortest_r_addr = [map(lambda x : self.graph_ref.node[x]["router_ref"].address, i) for i in shortest_routes]
 
 
            # NOTE about routing tables: need to think about which routes based on 
            # NOTE about routing tables: need to think about which routes based on 
            # shortest paths are better in general with other routers, so the links
            # shortest paths are better in general with other routers, so the links
            # are well balanced. A possible problem could be that some links will carry
            # are well balanced. A possible problem could be that some links will carry
            # more data flow than others.
            # more data flow than others.
            # A possible workaround lies in the generation of routing tables at
            # A possible workaround lies in the generation of routing tables at
            # NoC level, taking account of neighbors tables and others parameters.
            # NoC level, taking account of neighbors tables and others parameters.
 
 
            # extract the next neighbor in each path
            # extract the next neighbor in each path
            for route in shortest_r_addr:
            for route in shortest_r_addr:
                # first element is myself, last element is its destination. 
                # first element is myself, last element is its destination. 
                # for this routing table, we only need the next router to
                # for this routing table, we only need the next router to
                # send the package.
                # send the package.
                newroute = True
                newroute = True
                for route_entry in self.routes_info[destrouter.index]:
                for route_entry in self.routes_info[destrouter.index]:
                    if route[1] == route_entry["next"]:
                    if route[1] == route_entry["next"]:
                        # another route which next element was taken account
                        # another route which next element was taken account
                        route_entry["paths"].append(route)
                        route_entry["paths"].append(route)
                        newroute = False
                        newroute = False
                if newroute:
                if newroute:
                    self.routes_info[destrouter.index].append({"next": route[1], "paths": [route]})
                    self.routes_info[destrouter.index].append({"next": route[1], "paths": [route]})
            # last option: send through another node not in the shortest paths 
            # last option: send through another node not in the shortest paths 
            # NOTE: decide if this is needed or make sense
            # NOTE: decide if this is needed or make sense
 
 
class channel(nocobject):
class channel(nocobject):
    """
    """
    Channel base object
    Channel base object
 
 
    This object represents a channel object and its properties. This base class
    This object represents a channel object and its properties. This base class
    is meant to either be inherited or extended by adding other attributes.
    is meant to either be inherited or extended by adding other attributes.
 
 
    Relations with other objects:
    Relations with other objects:
    * It should be related to one NoC model object (self.graph_ref)
    * It should be related to one NoC model object (self.graph_ref)
    * It may be one of the edge attributes in the graph model
    * It may be one of the edge attributes in the graph model
      (edge["channel_ref"]). In this case, this channel connects two routers
      (edge["channel_ref"]). In this case, this channel connects two routers
      in the NoC model.
      in the NoC model.
    * It should have two references to NoC objects (self.endpoints). Two options
    * It should have two references to NoC objects (self.endpoints). Two options
      exists: two routers references (channel has an edge object) or, one
      exists: two routers references (channel has an edge object) or, one
      router and one ipcore (channel don't have any edge object).
      router and one ipcore (channel don't have any edge object).
 
 
    Attributes:
    Attributes:
    * name
    * name :
    * index: optional index on a noc object. Must have an index when it has
    * index: optional index on a noc object. Must have an index when it has
      a related edge in the graph model (and allowing it to be able to do
      a related edge in the graph model (and allowing it to be able to do
      channel searching). None means it is an ipcore related channel
      channel searching). None means it is an ipcore related channel
    * graph_ref optional reference to its graph model
    * graph_ref : optional reference to its graph model
    * endpoints optional two-item list with references to the connected objects
    * endpoints : optional two-item list with references to the connected objects
 
    * intercon_class : optional reference to a intercon class used in this channel.
    """
    """
    def __init__(self, name, index=None, **kwargs):
    def __init__(self, name, index=None, **kwargs):
        # Basic properties
        # Basic properties
        self.index = index
        self.index = index
        self.name = name
        self.name = name
        # Default values
        # Default values
        self.graph_ref = None
        self.graph_ref = None
        self.endpoints = [None, None]
        self.endpoints = [None, None]
 
        self.intercon_class = intercon
 
        self.intercon_class_defargs = {}
        for key in kwargs.keys():
        for key in kwargs.keys():
            setattr(self, key, kwargs[key])
            setattr(self, key, kwargs[key])
 
        # ports structure
 
        self.ports = {}
 
 
 
    # update functions: call them when the underlying NoC structure
 
    # has changed
 
    def update_ports_info(self, intercon_class=None):
 
        """
 
        Update the dictionary "ports": For a channel, there is two
 
        elements referencing both connected objects
 
 
 
        Ports dictionary has the following structure:
 
        * key: address of the router related with this channel, or None
 
            for a ipcore object.
 
        * value: dictionary with the following keys:
 
            * "peer" (required): reference to the router or ipcore
 
            * "channel" (required): reference to self
 
            * "intercon" (required for RTL sim and codegen)
 
            * Optional keys can be added to this dictionary.
 
 
 
        Arguments :
 
        * intercon_class : class reference to generate intercon instances
 
        NOTE:
 
        * This update will change and DESTROY existing intercon objects.
 
        """
 
        if intercon_class is None:
 
            intercon_class = self.intercon_class
 
        if not issubclass(intercon_class,  intercon):
 
            raise TypeError("intercon_class must be subclass of intercon.")
 
        self.ports = {}
 
        for endp in self.endpoints:
 
            if isinstance(endp, ipcore):
 
                idx = None
 
            elif isinstance(endp, router):
 
                idx = endp.get_address()
 
            else:
 
                raise ValueError("endpoints has an inconsistent state (%s)." % repr(endp))
 
            self.ports[idx] = {}
 
            self.ports[idx]["peer"] = endp
 
            self.ports[idx]["channel"] = self
 
            # TEMPORAL WORKAROUND: use intercon_class.complement on ipcore side
 
            # ONLY on case of ipcore channels.
 
            if idx == None and hasattr(intercon_class, "complement"):
 
                self.ports[idx]["intercon"] = intercon_class.complement(name=endp.name, **self.intercon_class_defargs)
 
            else:
 
                self.ports[idx]["intercon"] = intercon_class(name=endp.name, **self.intercon_class_defargs)
 
 
    def is_ipcore_link(self):
    def is_ipcore_link(self):
        """
        """
        Checks if this channel is a special link for an ipcore.
        Checks if this channel is a special link for an ipcore.
 
 
        Return: True if the channel is related to an ipcore
        Return: True if the channel is related to an ipcore
        """
        """
        # Search for ipcore in endpoints. Don't check None on self.index.
        # Search for ipcore in endpoints. Don't check None on self.index.
        for ref in self.endpoints:
        for ref in self.endpoints:
            if isinstance(ref, ipcore):
            if isinstance(ref, ipcore):
                return True
                return True
        return False
        return False
 
 
class protocol(nocobject):
# ****************************************
 
# Generic models for abstract NoC elements
 
# ****************************************
 
 
 
# physical and data-link layers
 
class intercon():
 
    """
 
    Interconnection base object
 
 
 
    This object models the interconnection that use a port in a NoC object.
 
    It defines at physical and data-link level how is the connection between
 
    ports of the NoC object.
 
 
 
    Relations with other objects:
 
    * Each port of a NoC object (routers, channels and ipcores) must have
 
        an instance of a intercon object (object.ports[index]["intercon"])
 
    * A NoC model may have one or various references to intercon classes, in
 
        order to provide object constructors for different ports in the NoC
 
        objects.
 
 
 
    Attributes:
 
    * name :
 
    * intercon_type : string to identify intercon type
 
    * complement : reference to a class that provides its reciprocal intercon
 
    * description : a string with a brief description
 
    * long_desc : a long string with a detailed description, usually formatted
 
      in reST (as any Python help string).
 
    * signals : dictionary with the list of signals. The structure is:
 
        * keys : signal's name
 
        * values :
 
            * "width" : bit length of this signal
 
            * "direction" : "in" or "out"
 
            * "signal_obj" : (only simulation) MyHDL signal reference
 
            * "description" :
 
            * Optional keys can be added to this dictionary.
 
 
 
    Notes:
 
    * To avoid excessive duplication of intercon objects, we assume the following
 
      convention for symmetrical intercons: only channels will create new
 
      instances; routers and ipcores only can hold references to this instances.
 
      In case of asymmetrical intercons (master/slave schemes), routes and
 
      ipcores can create new instances, based on intercon type on channel.
 
    """
 
    def __init__(self, name="", **kwargs):
 
        self.name = name
 
        self.intercon_type = ""
 
        self.description = ""
 
        self.long_desc = ""
 
        for key in kwargs.keys():
 
            setattr(self, key, kwargs[key])
 
        # complementary class: None means myself
 
        self.complement = None
 
        # signals info (ordered dict)
 
        self.signals = OrderedDict()
 
 
 
    def __repr__(self):
 
        if self.name != "":
 
            return "<%s '%s'>" % (self.__class__.__name__, self.name)
 
        else:
 
            return "<%s at '%d'>" % (self.__class__.__name__, id(self))
 
 
 
    def add_signal(self, signalname, direction, bitwidth, signalref=None, description=""):
 
        """
 
        Add a signal entry to the intercon
 
 
 
        Arguments:
 
        * signalname: signal name on this intercon
 
        * direction: "in" or "out"
 
        * bitwidth: must be >= 1
 
        * signalref: optional MyHDL signal
 
        * description:
 
 
 
        Returns:
 
        * The contents of signalref
 
        """
 
        if not isinstance(signalname, str):
 
            raise ValueError("Signalname must be an string (not %s)" % repr(signalname))
 
        if direction not in ("in", "out"):
 
            raise ValueError("Direction must be either 'in' or 'out' (not %s)" % repr(direction))
 
        if bitwidth <= 0:
 
            raise ValueError("Bitwidth must be greater than 0 (not %s)" % repr(bitwidth))
 
 
 
        if signalref is not None:
 
            if not isinstance(signalref, SignalType):
 
                raise ValueError("Signalref %s must be a MyHDL Signal (not %s, type %s)" % (signalname, repr(signalref), type(signalref)))
 
 
 
        self.signals[signalname] = {"width": bitwidth, "direction": direction, "signal_obj": signalref, "description": description}
 
 
 
        return signalref
 
 
 
    def get_signal_info(self, signalname, field=None):
 
        """
 
        Search the signal in the intercon and return signal information.
 
        Raise exceptions if the signal is not found, or if the field doesn't
 
        exist for this signal.
 
 
 
        Arguments:
 
        * signalname: signal name on this intercon
 
        * field: particular key of this signal info. None to return
 
                all fields in a dict.
 
 
 
        Returns:
 
        * A dict with the signal information, if field is None.
 
        * The particular object with the key "field" in the signal
 
            info dict.
 
        """
 
        if signalname not in self.signals:
 
            raise KeyError("Signal '%s' not found" % signalname)
 
        if field is None:
 
            return self.signals[signalname]
 
        else:
 
            if field not in self.signals[signalname]:
 
                raise KeyError("Signal '%s': field %s not found" % (signalname, repr(field)))
 
            else:
 
                return self.signals[signalname][field]
 
 
 
    def get_signal_ref(self, signalname=None):
 
        """
 
        Return the MyHDL signal object
 
 
 
        Arguments:
 
        * signalname: name to search, or None
 
 
 
        Returns:
 
        * The signal reference
 
        * If signalname is None, returns a dict with all available
 
            signal objects.
 
        """
 
        if signalname is not None:
 
            return self.get_signal_info(signalname, "signal_obj")
 
        else:
 
            # dict with all available MyHDL signal references
 
            retval = OrderedDict()
 
            for key, val in self.signals.iteritems():
 
                if isinstance(val["signal_obj"], SignalType):
 
                    retval[key] = val["signal_obj"]
 
            return retval
 
 
 
    def get_signal_allnames(self):
 
        """
 
        Return a list of signal names
 
        """
 
        return self.signals.keys()
 
 
 
    def create_myhdl_signals(self):
 
        """
 
        Make MyHDL Signal objects for each signal entry.
 
 
 
        Returns: A dict with all the created signal objects
 
        Note: Previous signal objects will be *unreferenced*.
 
        """
 
        retval = OrderedDict()
 
        for key, sig in self.signals.iteritems():
 
            # use bool for 1-bit signals
 
            if sig["width"] == 1:
 
                sig["signal_obj"] = Signal(bool(0))
 
            else:
 
                sig["signal_obj"] = Signal(intbv(0)[sig["width"]:])
 
            retval[key] = sig["signal_obj"]
 
        return retval
 
 
 
    def get_complement_signal(self, signalname):
 
        """
 
        Get the signal name that should be connected to this signal when
 
        connecting two intercon.
 
 
 
        Arguments:
 
        * signalname: signal name of this intercon
 
 
 
        Return: a string with the name of a signal from a complementary intercon.
 
        """
 
        return None
 
 
 
    def create_complementary(self, newname="", **kwargs):
 
        """
 
        Create a instance of a complementary type
 
 
 
        Arguments:
 
        * newname : optional new name for the created object. By default use
 
          the same name as self.
 
        * optional list of arguments to use for new object. By default the
 
          created object copy its attributes from this object.
 
        """
 
        # prepare list of arguments
 
        if newname == "":
 
            newname = self.name
 
        if "name" not in kwargs:
 
            kwargs["name"] = newname
 
        # extract list of attributes, excluding some...
 
        names = filter(lambda s: s[1] != "_", dir(self))
 
        names = filter(lambda s: s not in ("name", "intercon_type", "complement", "signals", "sigmapping"), names)
 
        # and, if not defined in kwargs, use self attributes
 
        for s in names:
 
            if s not in kwargs:
 
                kwargs[s] = getattr(self, s)
 
 
 
        if self.complement is None:
 
            # I'm my complement? like a object clone
 
            # use my class reference, so the constructor is correctly called.
 
            return self.__class__(**kwargs)
 
        else:
 
            return self.complement(**kwargs)
 
 
 
# Special intercon to implement a signal container
 
class signalset(intercon):
 
    """
 
    Signal container based on an intercon.
 
 
 
    Attributes:
 
    * name :
 
    * intercon_type : "signalset"
 
    * complement : Without complement intercon by default
 
    * description :
 
    * signals : dictionary with the list of signals. The structure is:
 
        * keys : signal's name
 
        * values :
 
            * "width" : bit length of this signal
 
            * "direction" : "in" or "out"
 
            * "signal_obj" : MyHDL signal reference
 
            * "description" :
 
            * Optional keys can be added to this dictionary.
 
 
 
    Notes:
 
    * This object makes a MyHDL signal when method "add_signal" is used.
 
    * This object implements a custom complement signal mechanism.
 
    """
 
 
 
    def __init__(self, name, **kwargs):
 
        intercon.__init__(self, name, **kwargs)
 
        self.complement_mapping = {}
 
 
 
        self.intercon_type = "signalset"
 
        self.complement = None
 
        self.sideinfo = ""
 
 
 
    def add_signal(self, signalname, direction, bitwidth, signalref=None, complname=None, description=""):
 
        """
 
        Add a signal entry to signalset
 
 
 
        Arguments:
 
        * signalname:
 
        * direction: "in" or "out"
 
        * bitwidth: must be >= 1
 
        * signalref: optional MyHDL signal. If None, it will create a new signal.
 
        * complname: optional complement signal name. This string will be
 
            returned on "get_complement_signal" method.
 
        * description:
 
 
 
        Returns:
 
        * The contents of signalref
 
        """
 
        intercon.add_signal(self, signalname, direction, bitwidth, signalref, description)
 
 
 
        # need signal creation at this point
 
        if signalref is None:
 
            if bitwidth == 1:
 
                signalref = Signal(bool(0))
 
            else:
 
                signalref = Signal(intbv(0)[bitwidth:])
 
            self.signals[signalname]["signal_obj"] = signalref
 
 
 
        # complement signal mapping
 
        if isinstance(complname, str):
 
            self.complement_mapping[signalname] = complname
 
 
 
        return signalref
 
 
 
    def get_complement_signal(self, signalname):
 
        """
 
        Get the signal name that should be connected to this signal when
 
        connecting two signalref (or intercon). Return value depends on
 
        signal creation arguments (see "add_signal" method)
 
 
 
        Arguments:
 
        * signalname: signal name of this intercon
 
 
 
        Return: a string with complementary signal name, or None if not found.
 
        """
 
        if signalname not in self.signals:
 
            raise KeyError("Signal '%s' not found" % signalname)
 
 
 
        if signalname in self.complement_mapping:
 
            return self.complement_mapping[signalname]
 
        else:
 
            return None
 
 
 
# network and transport layers
 
class protocol():
    """
    """
    Protocol base object
    Protocol base object
 
 
    This object represents the protocol that the NoC objects use. This
    This object represents the protocol that the NoC objects use. This
    object has attributes that define the protocol used, mainly it can be
    object has attributes that define the protocol used, mainly it can be
    used to generate, encode, decode or interpret packets on the NoC.
    used to generate, encode, decode or interpret packets on the NoC.
    This base class can be either be inherited or extended by adding
    This base class can be either be inherited or extended by adding
    other attributes.
    other attributes.
 
 
    Relations with other objects:
    Relations with other objects:
    * Each object on the NoC (routers, channels and ipcores) may have
    * Each object on the NoC (routers, channels and ipcores) may have
      one reference to a protocol object (object.protocol_ref)
      one reference to a protocol object (object.protocol_ref)
    * A NoC model may have a protocol object: in this case, all objects in
    * A NoC model may have a protocol object: in this case, all objects in
      the model will use this protocol (nocmodel.protocol_ref)
      the model will use this protocol (nocmodel.protocol_ref)
    * A protocol object is a generator of packet objects
    * A protocol object is a generator of packet objects
 
 
    Attributes:
    Attributes:
    * name
    * name
 
    * description : a string with a brief description
 
    * long_desc : a long string with a detailed description, usually formatted
 
      in reST (as any Python help string).
 
 
    Notes:
    Notes:
    * Optional arguments "packet_format" and "packet_order" can be
    * Optional arguments "packet_format" can be
      added at object construction, but will not check its data consistency.
      added at object construction, but will not check its data consistency.
      At the moment, we recommend using update_packet_field() method to
      At the moment, we recommend using update_packet_field() method to
      fill this data structures.
      fill this data structures.
    """
    """
    def __init__(self, name="", **kwargs):
    def __init__(self, name="", **kwargs):
        """
        """
        Constructor
        Constructor
 
 
        Notes:
        Notes:
        * Optional arguments will be added as object attributes.
        * Optional arguments will be added as object attributes.
        """
        """
        # NOTE: to avoid python version requirements (2.7), implement ordered 
 
        # dict with an additional list. When we are sure of using 
 
        # Python > 2.7 , change to collections.OrderedDict
 
        self.name = name
        self.name = name
        self.packet_format = {}
        self.packet_format = OrderedDict()
        self.packet_order = []
 
        self.packet_class = packet
        self.packet_class = packet
 
        self.packet_bitlen = 0
 
        self.flit_bitlen = 0
 
        self.flit_fixcount = 0
 
        self.flit_padbits = 0
 
        self.variable_packet = False
 
        self.description = ""
 
        self.long_desc = ""
        for key in kwargs.keys():
        for key in kwargs.keys():
            setattr(self, key, kwargs[key])
            setattr(self, key, kwargs[key])
 
 
    def get_protocol_ref(self):
    def __repr__(self):
        # override to use myself
        if self.name != "":
        return self
            return "<%s '%s'>" % (self.__class__.__name__, self.name)
 
        else:
 
            return "<%s at '%d'>" % (self.__class__.__name__, id(self))
 
 
    def update_packet_field(self, name, type, bitlen, description=""):
    def update_packet_field(self, name, type, bitlen, description=""):
        """
        """
        Add or update a packet field.
        Add or update a packet field.
 
 
        Arguments
        Arguments
        * name
        * name
        * type: string that can be "int", "fixed" or "float"
        * type: string that can be "int", "uint", "fixed" or "float"
        * bitlen: bit length of this field
        * bitlen: bit length of this field
        * description: optional description of this field
        * description: optional description of this field
 
 
        Notes:
        Notes:
        * Each new field will be added at the end.
        * Each new field will be added at the end.
 
        * Fields are configured to have a bit range inside the packet,
 
        *  starting at 0. Also, it refers to the fixed part of the packet.
 
        * Fields "msb" and "lsb" are indexes relative to MSB bit of the first
 
           field (Big endian scheme), completely different to a
 
           bit vector indexing.
        """
        """
        if (type != "int") and (type != "fixed") and (type != "float"):
        if type not in ("int", "uint", "fixed", "float"):
            raise ValueError("Argument 'type' must be 'int', 'fixed' or 'float'.")
            raise ValueError("Argument 'type' must be 'int', 'uint', 'fixed' or 'float'.")
 
 
        if name in self.packet_format:
        if name in self.packet_format:
            # update field
            # update field
            previdx = self.packet_order.index(name) - 1
            previdx = self.packet_format.keys().index(name) - 1
            if previdx < 0:
            if previdx < 0:
                # first field
                # first field
                lastbitpos = 0
                lastbitpos = 0
            else:
            else:
                lastbitpos = self.packet_format[self.packet_order[previdx]][lsb]
                lastbitpos = self.packet_format[self.packet_format.keys()[previdx]]["lsb"]
            nextbitpos = lastbitpos + bitlen
            nextbitpos = lastbitpos + bitlen
            self.packet_format[name]["type"] = type
            self.packet_format[name]["type"] = type
            self.packet_format[name]["position"] = previdx + 1
            self.packet_format[name]["position"] = previdx + 1
            # check if the packet format needs to adjust the bit positions
            # check if the packet format needs to adjust the bit positions
            if self.packet_format[name]["bitlen"] != bitlen:
            if self.packet_format[name]["bitlen"] != bitlen:
                self.packet_format[name]["bitlen"] = bitlen
                self.packet_format[name]["bitlen"] = bitlen
                self.packet_format[name]["lsb"] = nextbitpos
                self.packet_format[name]["lsb"] = nextbitpos
                self.packet_format[name]["msb"] = lastbitpos
                self.packet_format[name]["msb"] = lastbitpos
                # iterate through the rest of the fields adjusting lsb and msb
                # iterate through the rest of the fields adjusting lsb and msb
                for idx in range(previdx+2, len(self.packet_order)):
                for idx in range(previdx+2, len(self.packet_format.keys())):
                    curname = self.packet_order[idx]
                    curname = self.packet_format.keys()[idx]
                    curbitlen = self.packet_format[curname]["bitlen"]
                    curbitlen = self.packet_format[curname]["bitlen"]
                    self.packet_format[curname]["lsb"] = nextbitpos + curbitlen
                    self.packet_format[curname]["lsb"] = nextbitpos + curbitlen
                    self.packet_format[curname]["msb"] = nextbitpos
                    self.packet_format[curname]["msb"] = nextbitpos
                    nextbitpos += curbitlen
                    nextbitpos += curbitlen
 
            self.packet_bitlen = nextbitpos
        else:
        else:
            # append
            # append
            if len(self.packet_format) == 0:
            if len(self.packet_format) == 0:
                lastbitpos = 0
                lastbitpos = 0
            else:
            else:
                lastbitpos = self.packet_format[self.packet_order[-1]]["lsb"]
                lastbitpos = self.packet_format[self.packet_format.keys()[-1]]["lsb"] + 1
            nextbitpos = lastbitpos + bitlen
            nextbitpos = lastbitpos + bitlen
            fieldpos = len(self.packet_order)
            fieldpos = len(self.packet_format)
            self.packet_format[name] = {"type": type, "position": fieldpos, "bitlen": bitlen, "lsb": nextbitpos, "msb": lastbitpos}
            self.packet_format[name] = {"type": type, "position": fieldpos, "bitlen": bitlen, "lsb": nextbitpos - 1, "msb": lastbitpos}
            self.packet_order.append(name)
            self.packet_bitlen = nextbitpos
 
 
 
    def get_field_info(self, name):
 
        """
 
        Get information about a existing packet field.
 
 
 
        Arguments:
 
        * name
 
        Returns a dict with the following information:
 
        * "type"
 
        * "pkt_bitpos": absolute bit position in the packet (msb)
 
        * "bitlen": bit size
 
        * "flit_num": which flit use this field
 
        * "flit_bitpos": bit position inside the flit
 
        """
 
        if name not in self.packet_format:
 
            raise ValueError("Packet field '%s' not found." % name)
 
        retinfo = {}
 
        retinfo["type"] = self.packet_format[name]["type"]
 
        retinfo["bitlen"] = self.packet_format[name]["bitlen"]
 
        retinfo["pkt_bitpos"] = self.packet_format[name]["msb"]
 
        if getattr(self, "flit_bitlen", 0) == 0:
 
            # not using flits
 
            retinfo["flit_num"] = 0
 
            retinfo["flit_position"] = self.packet_format[name]["msb"]
 
        else:
 
            # CHECK THIS
 
            retinfo["flit_num"] = int(self.packet_format[name]["msb"] / self.flit_bitlen)
 
            retinfo["flit_position"] = self.packet_format[name]["msb"] - retinfo["flit_num"]
 
 
 
        return retinfo
 
 
 
    def configure_flits(self, flit_size, variable_packet=False):
 
        """
 
        Configure the flit split in a packet.
 
 
 
        Arguments:
 
        * flit_size: size in bits of a flit. Based on this size a packet
 
          is split, and a zero padding added if necessary.
 
        * variable_packet: If true, allows the packet to have a variable
 
          packet size by adding additional flits at the end.
 
 
 
        NOTE: variable packet mechanism is still under development.
 
        """
 
        if flit_size <= 0:
 
            raise ValueError("Argument 'flit_size' must be greater than zero.")
 
        self.flit_bitlen = flit_size
 
        # calculate the number of flits of the fixed part of the packet
 
        self.flit_fixcount = int(mathceil(float(self.packet_bitlen) / float(self.flit_bitlen)))
 
        self.flit_padbits = (self.flit_fixcount*self.flit_bitlen) - self.packet_bitlen
 
        self.variable_packet = variable_packet
 
 
    def newpacket(self, zerodefault=True, *args, **kwargs):
    def newpacket(self, zerodefault=True, *args, **kwargs):
        """
        """
        Return a new packet with all required fields.
        Return a new packet with all required fields.
 
 
        Arguments:
        Arguments:
        * zerodefault: If True, all missing fields will be zeroed by default.
        * zerodefault: If True, all missing fields will be zeroed by default.
          If False, a missing value in arguments will throw an exception.
          If False, a missing value in arguments will throw an exception.
        * args: Nameless arguments will add field values based on packet field
        * args: Nameless arguments will add field values based on packet field
          order.
          order.
        * kwargs: Key-based arguments will add specified field values based in
        * kwargs: Key-based arguments will add specified field values based in
          its keys
          its keys
 
 
        Notes:
        Notes:
        * kwargs takes precedence over args: i.e. named arguments can overwrite
        * kwargs takes precedence over args: i.e. named arguments can overwrite
          nameless arguments.
          nameless arguments.
        """
        """
        retpacket = self.packet_class(protocol_ref=self)
        retpacket = self.packet_class(protocol_ref=self)
        fieldlist = self.packet_order[:]
        fieldlist = self.packet_format.keys()
        # first named arguments
        # first named arguments
        for fkey, fvalue in kwargs.iteritems():
        for fkey, fvalue in kwargs.iteritems():
            if fkey in fieldlist:
            if fkey in fieldlist:
                retpacket[fkey] = fvalue
                retpacket[fkey] = fvalue
                fieldlist.remove(fkey)
                fieldlist.remove(fkey)
        # then nameless
        # then nameless
        for fidx, fvalue in enumerate(args):
        for fidx, fvalue in enumerate(args):
            fkey = self.packet_order[fidx]
            fkey = self.packet_format.keys()[fidx]
            if fkey in fieldlist:
            if fkey in fieldlist:
                retpacket[fkey] = fvalue
                retpacket[fkey] = fvalue
                fieldlist.remove(fkey)
                fieldlist.remove(fkey)
        # check for empty fields
        # check for empty fields
        if len(fieldlist) > 0:
        if len(fieldlist) > 0:
            if zerodefault:
            if zerodefault:
                for fkey in fieldlist:
                for fkey in fieldlist:
                    retpacket[fkey] = 0
                    retpacket[fkey] = 0
            else:
            else:
                raise ValueError("Missing fields in argument list: %s" % repr(fieldlist))
                raise ValueError("Missing fields in argument list: %s" % repr(fieldlist))
        return retpacket
        return retpacket
 
 
 
    def newpacket_frombinary(self, binaryinput):
 
        """
 
        Return a new packet based on a binary representation
 
 
 
        Arguments:
 
        * binaryinput: integer or intbv with the binary representation
 
          of the packet.
 
        """
 
        if isinstance(binaryinput, (int, long)):
 
            theinput = intbv(binaryinput)[self.packet_bitlen:]
 
        elif isinstance(binaryinput, intbv):
 
            theinput = binaryinput
 
        else:
 
            raise ValueError("Unsupported type for binaryinput: '%s'" % repr(type(binaryinput)))
 
        retpacket = self.packet_class(protocol_ref=self)
 
        for field, field_info in self.packet_format.iteritems():
 
            # NOTE: msb and lsb indexes are referred as 0 as the MSB bit
 
            # recalculate to have the LSB bit at 0
 
            msb = self.packet_bitlen - field_info["msb"]
 
            lsb = self.packet_bitlen - field_info["lsb"] - 1
 
            if field_info["type"] == "int":
 
                #retpacket[field] = theinput[msb:lsb].signed()
 
                retpacket[field] = theinput[msb:lsb]
 
            elif field_info["type"] == "uint":
 
                retpacket[field] = theinput[msb:lsb]
 
            else:
 
                raise NotImplementedError("Field %s type %s not supported yet." % (field, field_info["type"]))
 
        retpacket.prev_repr = binaryinput
 
        return retpacket
 
 
 
    def newpacket_fromflits(self, flits_list):
 
        """
 
        Return a new packet based on a list of flits
 
 
 
        Arguments:
 
        * flits_list: list of integers or intbv with the binary
 
          representation of each flit.
 
        """
 
        if not isinstance(flits_list, (list, tuple)):
 
            raise ValueError("Unsupported type for flits_list: '%s'" % repr(type(flits_list)))
 
        extracted = []
 
        flit_curbit = self.flit_bitlen
 
        flit_idx = 0
 
        for field, field_info in self.packet_format.iteritems():
 
            flit_val = intbv(0)[field_info["bitlen"]:]
 
 
 
            msb = flit_curbit
 
            lsb = flit_curbit - field_info["bitlen"]
 
 
 
            if lsb < 0:
 
 
 
                # split packet field into several flits
 
                lsb_pend = -lsb
 
 
 
                # first part
 
                flit_val[:lsb_pend] = flits_list[flit_idx][flit_curbit:]
 
 
 
                flit_idx += 1
 
                flit_curbit = self.flit_bitlen
 
 
 
                while lsb_pend > 0:
 
                    if lsb_pend >= self.flit_bitlen:
 
                        flit_val[lsb_pend:lsb_pend-self.flit_bitlen] = flits_list[flit_idx]
 
                        flit_idx += 1
 
                        flit_curbit = self.flit_bitlen
 
                        lsb_pend -= field_info["bitlen"]
 
                    else:
 
                        # last flit
 
                        flit_val[lsb_pend:] = flits_list[flit_idx][:self.flit_bitlen-lsb_pend]
 
                        flit_curbit -= lsb_pend
 
                        lsb_pend = 0
 
            else:
 
                flit_val = flits_list[flit_idx][msb:lsb]
 
                flit_curbit -= field_info["bitlen"]
 
 
 
            extracted.append(flit_val)
 
            if lsb == 0:
 
                # next flit
 
                flit_idx += 1
 
                flit_curbit = self.flit_bitlen
 
 
 
        retpacket = self.packet_class(protocol_ref=self)
 
        for field, content in zip(self.packet_format.keys(), extracted):
 
            if self.packet_format[field]["type"] == "int":
 
                #retpacket[field] = theinput[msb:lsb].signed()
 
                retpacket[field] = content
 
            elif self.packet_format[field]["type"] == "uint":
 
                retpacket[field] = content
 
            else:
 
                raise NotImplementedError("Field %s type %s not supported yet." % (field, self.packet_format[field]["type"]))
 
        retpacket.prev_repr = flits_list
 
        return retpacket
 
 
    def register_packet_generator(self, packet_class):
    def register_packet_generator(self, packet_class):
        """
        """
        Register a special packet generator class.
        Register a special packet generator class.
 
 
        Must be a derived class of packet
        Must be a derived class of packet
        """
        """
        if not issubclass(packet_class, packet):
        if not issubclass(packet_class, packet):
            raise TypeError("Argument 'packet_class' must derive from 'packet' class.")
            raise TypeError("Argument 'packet_class' must derive from 'packet' class.")
        self.packet_class = packet_class
        self.packet_class = packet_class
 
 
class packet(dict):
class packet(dict):
    """
    """
    Packet base object
    Packet base object
 
 
    This object represents a packet data, related to a protocol object. It
    This object represents a packet data, related to a protocol object. It
    behaves exactly like a Python dictionary, but adds methods to simplify
    behaves exactly like a Python dictionary, but adds methods to simplify
    packet transformations.
    packet transformations.
 
 
    Relations with other objects:
    Relations with other objects:
    * It should be generated by a protocol object (and will have a reference
    * It should be generated by a protocol object (and will have a reference
      in self.protocol_ref)
      in self.protocol_ref)
 
 
    Attributes:
    Attributes:
    * protocol_ref: protocol object that created this object.
    * protocol_ref: protocol object that created this object.
 
    * prev_repr: previous representation of this packet. Can be:
 
      - None: this packet was created by each field data
 
      - <type long> : was created with a numeric representation.
 
      - <type list> : was created with a list of flits
 
      This attribute should only be changed by its protocol object.
    """
    """
 
 
 
    # TODO: add support for flit construction: temporal storage for flits,
 
    # and package construction after final flit
 
 
    # the constructor 
    # the constructor 
    def __init__(self, *args, **kwargs):
    def __init__(self, *args, **kwargs):
        # look for a protocol_ref key
        # look for a protocol_ref key
        self.protocol_ref = kwargs.pop("protocol_ref", None)
        self.protocol_ref = kwargs.pop("protocol_ref", None)
 
        self.prev_repr = None
        dict.__init__(self, *args, **kwargs)
        dict.__init__(self, *args, **kwargs)
 
 
 
 
 
    # override copy method
 
    def copy(self):
 
        # Warning: take account of each element inside, specially if it's 
 
        # a intbv
 
        basedict = dict(**self)
 
        for k, v in self.iteritems():
 
            if isinstance(v, intbv):
 
                # make a copy
 
                basedict[k] = intbv(v)
 
        # use same keys to build the new packet
 
        pktobj = packet(**basedict)
 
        pktobj.protocol_ref = self.protocol_ref
 
        pktobj.prev_repr = self.prev_repr
 
        return pktobj
 
 
 
    def get_flit_repr(self):
 
        """
 
        Returns a list of integers with the binary representation of the
 
        full packet contents, separated in flits.
 
        """
 
        protocol_ref = self.protocol_ref
 
        binary_flits = [intbv(0)[protocol_ref.flit_bitlen:] for i in range(protocol_ref.flit_fixcount)]
 
        flit_curbit = protocol_ref.flit_bitlen
 
        flit_idx = 0
 
        for field, field_info in protocol_ref.packet_format.iteritems():
 
            if field_info["type"] == "int" or field_info["type"] == "uint":
 
                bitvalue = intbv(self[field])[field_info["bitlen"]:]
 
            elif field_info["type"] == "fixed":
 
                raise NotImplementedError("Don't know how to put a fixed point in a binary representation.")
 
            elif field_info["type"] == "float":
 
                raise NotImplementedError("Don't know how to put a float in a binary representation.")
 
 
 
            #{"type": type, "position": fieldpos, "bitlen": bitlen, "lsb": nextbitpos, "msb": lastbitpos}
 
            msb_flit = flit_curbit
 
            lsb_flit = flit_curbit - field_info["bitlen"]
 
 
 
            if lsb_flit < 0:
 
                # split packet field into several flits
 
                lsb_flit_pend = -lsb_flit
 
 
 
                # first flit
 
                binary_flits[flit_idx][msb_flit:] = bitvalue[field_info["bitlen"]:flit_curbit]
 
                flit_idx += 1
 
                flit_curbit = protocol_ref.flit_bitlen
 
                while lsb_flit_pend > 0:
 
                    if lsb_flit_pend >= protocol_ref.flit_bitlen:
 
                        binary_flits[flit_idx] = bitvalue
 
                        flit_idx += 1
 
                        flit_curbit = protocol_ref.flit_bitlen
 
                        lsb_flit_pend -= field_info["bitlen"]
 
                    else:
 
                        # last flit
 
                        binary_flits[flit_idx][:protocol_ref.flit_bitlen - lsb_flit_pend] = bitvalue[lsb_flit_pend:]
 
                        flit_curbit -= lsb_flit_pend
 
 
 
            else:
 
                binary_flits[flit_idx][msb_flit:lsb_flit] = bitvalue
 
                flit_curbit -= field_info["bitlen"]
 
 
 
            if lsb_flit == 0:
 
                # next flit
 
                flit_idx += 1
 
                flit_curbit = protocol_ref.flit_bitlen
 
            #print "integer repr: FIELD %s bitval %d b%s\n field info %s recalc msb %d lsb %d" % (field, bitvalue, bin(bitvalue), repr(field_info), msb, lsb)
 
 
 
            #print "integer repr: TEMP BIN %d b%s" % (binaryout, bin(binaryout))
 
        #print "integer repr: FINAL BIN %d b%s" % (binaryout, bin(binaryout))
 
        return binary_flits
 
 
 
    def get_integer_repr(self):
 
        """
 
        Returns an integer with the binary representation of the
 
        full packet contents.
 
        """
 
        protocol_ref = self.protocol_ref
 
        #binaryout = 0
 
        binaryout = intbv(0)[protocol_ref.packet_bitlen:]
 
        for field, field_info in protocol_ref.packet_format.iteritems():
 
            bitvalue = self[field]
 
            #{"type": type, "position": fieldpos, "bitlen": bitlen, "lsb": nextbitpos, "msb": lastbitpos}
 
            # NOTE: msb and lsb indexes are referred as 0 as the MSB bit
 
            # recalculate to have the LSB bit at 0
 
            msb = protocol_ref.packet_bitlen - field_info["msb"]
 
            lsb = protocol_ref.packet_bitlen - field_info["lsb"] - 1
 
            #print "integer repr: FIELD %s bitval %d b%s\n field info %s recalc msb %d lsb %d" % (field, bitvalue, bin(bitvalue), repr(field_info), msb, lsb)
 
            if field_info["type"] == "int" or field_info["type"] == "uint":
 
                #binaryout |= (bitvalue << lsb)
 
                binaryout[msb:lsb] = intbv(bitvalue)[field_info["bitlen"]:]
 
            elif field_info["type"] == "fixed":
 
                raise NotImplementedError("Don't know how to put a fixed point in a binary representation.")
 
            elif field_info["type"] == "float":
 
                raise NotImplementedError("Don't know how to put a float in a binary representation.")
 
            #print "integer repr: TEMP BIN %d b%s" % (binaryout, bin(binaryout))
 
        #print "integer repr: FINAL BIN %d b%s" % (binaryout, bin(binaryout))
 
        return binaryout
 
 
 
 
# *******************************
# *******************************
# Additional functions
# Additional functions
# *******************************
# *******************************
 
 
# Missing function in NetworkX
# Missing function in NetworkX
def all_shortest_paths(G,a,b):
def all_shortest_paths(G,a,b):
    """
    """
    Return a list of all shortest paths in graph G between nodes a and b
    Return a list of all shortest paths in graph G between nodes a and b
    This is a function not available in NetworkX (checked at 22-02-2011)
    This is a function not available in NetworkX (checked at 22-02-2011)
 
 
    Taken from:
    Taken from:
    http://groups.google.com/group/networkx-discuss/browse_thread/thread/55465e6bb9bae12e
    http://groups.google.com/group/networkx-discuss/browse_thread/thread/55465e6bb9bae12e
    """
    """
    ret = []
    ret = []
    pred = nx.predecessor(G,b)
    pred = nx.predecessor(G,b)
    if not pred.has_key(a):  # b is not reachable from a
    if not pred.has_key(a):  # b is not reachable from a
        return []
        return []
    pth = [[a,0]]
    pth = [[a,0]]
    pthlength = 1  # instead of array shortening and appending, which are relatively
    pthlength = 1  # instead of array shortening and appending, which are relatively
    ind = 0        # slow operations, we will just overwrite array elements at position ind
    ind = 0        # slow operations, we will just overwrite array elements at position ind
    while ind >= 0:
    while ind >= 0:
        n,i = pth[ind]
        n,i = pth[ind]
        if n == b:
        if n == b:
            ret.append(map(lambda x:x[0],pth[:ind+1]))
            ret.append(map(lambda x:x[0],pth[:ind+1]))
        if len(pred[n]) > i:
        if len(pred[n]) > i:
            ind += 1
            ind += 1
            if ind == pthlength:
            if ind == pthlength:
                pth.append([pred[n][i],0])
                pth.append([pred[n][i],0])
                pthlength += 1
                pthlength += 1
            else:
            else:
                pth[ind] = [pred[n][i],0]
                pth[ind] = [pred[n][i],0]
        else:
        else:
            ind -= 1
            ind -= 1
            if ind >= 0:
            if ind >= 0:
                pth[ind][1] += 1
                pth[ind][1] += 1
    return ret
    return ret
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.