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

Subversion Repositories nocmodel

[/] [nocmodel/] [trunk/] [nocmodel/] [noc_base.py] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 dargor
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
 
4
#
5
# NoC Base Objects
6
#
7
# Author:  Oscar Diaz
8
# Version: 0.1
9
# Date:    03-03-2011
10
 
11
#
12
# This code is free software; you can redistribute it and/or
13
# modify it under the terms of the GNU Lesser General Public
14
# License as published by the Free Software Foundation; either
15
# version 2.1 of the License, or (at your option) any later version.
16
#
17
# This code is distributed in the hope that it will be useful,
18
# but WITHOUT ANY WARRANTY; without even the implied warranty of
19
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20
# Lesser General Public License for more details.
21
#
22
# You should have received a copy of the GNU Lesser General Public
23
# License along with this library; if not, write to the
24
# Free Software  Foundation, Inc., 59 Temple Place, Suite 330,
25
# Boston, MA  02111-1307  USA
26
#
27
 
28
#
29
# Changelog:
30
#
31
# 03-03-2011 : (OD) initial release
32
#
33
 
34
"""
35
================
36
NoCmodel Base Objects
37
================
38
 
39
This module declares classes used on a Network-on-chip representation:
40
 
41
* NoC container class
42
    * Router base class
43
    * Channel base class
44
    * IPCore base class
45
    * Protocol base class
46
    * Packet class
47
"""
48
 
49
import networkx as nx
50
 
51
class noc(nx.Graph):
52
    """
53
    Base class for NoC modeling.
54
    Based on a Graph object that hold the NoC structure
55
 
56
    Arguments
57
    * kwargs: optional parameters to put as object attributes
58
    """
59
    def __init__(self, **kwargs):
60
        """
61
        NoCmodel constructor
62
        """
63
        nx.Graph.__init__(self, **kwargs)
64
 
65
    # objects management functions
66
    def add_router(self, name="", with_ipcore=False, **kwargs):
67
        """
68
        Create a base router object and add it to NoC model.
69
 
70
        Arguments
71
        * name: optional name for this router. By default has the form of
72
          "R_<index>"
73
        * with_ipcore: If True, add an ipcore to the created router.
74
        * kwargs: optional parameters to put as object attributes
75
 
76
        Return: reference to the created router object
77
        """
78
        #nodeidx = self._get_next_nodeidx()
79
        routernode = router(index=None, name=name, graph_ref=self, **kwargs)
80
        retval = self.add_router_from_object(routernode)
81
        if name == "":
82
            retval.name = "R_%d" % retval.index
83
        if with_ipcore:
84
            # kwargs are reserved for router creation, not for ipcore.
85
            self.add_ipcore(retval)
86
        return retval
87
 
88
    def add_router_from_object(self, router_ref):
89
        """
90
        Add an existing router object to NoC model.
91
 
92
        Use this function to add an object based on a derived class of
93
        base router defined in this module.
94
 
95
        Arguments
96
        * router_ref: reference to the router object
97
 
98
        Return: the same reference passed in router_ref
99
 
100
        Notes:
101
        * This function will change router_ref.index and router_ref.graph_ref
102
          attributes when inserted in the NoC model.
103
        """
104
        if not isinstance(router_ref, router):
105
            raise ValueError("Argument 'router_ref' is not a router object.")
106
 
107
        router_ref.index = self._get_next_nodeidx()
108
        router_ref.graph_ref = self
109
        # don't forget that index is used for address
110
        router_ref.address = router_ref.index
111
        self.add_node(router_ref.index, router_ref=router_ref)
112
        return router_ref
113
 
114
    def add_channel(self, router1, router2, name="", **kwargs):
115
        """
116
        Create a base channel object to link two objects and add it
117
        to NoC model.
118
 
119
        Arguments:
120
        * router1: reference to a router, router index or ipcore
121
        * router2: -idem-
122
        * name: optional argument for channel name
123
        * kwargs: optional parameters to put as object attributes
124
 
125
        Notes:
126
        * If router1 or router2 is an ipcore reference, this method creates
127
          the special channel object and update ipcore references. Additionally,
128
          if both arguments are ipcores, throw an error exception
129
        """
130
        if isinstance(router1, ipcore) and isinstance(router2, ipcore):
131
            raise ValueError("Both object references cannot be ipcore objects.")
132
 
133
        rhash = [None, None]
134
        rrefs = [None, None]
135
        for targetid, routertarget in enumerate((router1, router2)):
136
            if isinstance(routertarget, router):
137
                if routertarget.index in self.node:
138
                    rhash[targetid] = routertarget.index
139
                    rrefs[targetid] = self.node[routertarget.index]["router_ref"]
140
            elif isinstance(routertarget, ipcore):
141
                # special channel
142
                rhash[targetid] = None
143
                rrefs[targetid] = routertarget
144
            elif isinstance(routertarget, int):
145
                if routertarget in self.node:
146
                    rhash[targetid] = routertarget
147
                    rrefs[targetid] = self.node[routertarget]["router_ref"]
148
 
149
        if rrefs[0] is None:
150
            raise ValueError("Object not found for argument 'router1'")
151
        if rrefs[1] is None:
152
            raise ValueError("Object not found for argument 'router2'")
153
 
154
        if None in rhash:
155
            ipcore_idx = rhash.index(None)
156
            # ipcore channel
157
            if name == "":
158
                # channel default name format 
159
                name = "CH_IP_%s" % rrefs[ipcore_idx].name
160
            channelnode = channel(index=None, name=name, graph_ref=self, **kwargs)
161
        else:
162
            # inter-routers channel
163
            if name == "":
164
                # channel default name format 
165
                name = "CH_%s:%s" % (rrefs[0].name, rrefs[1].name)
166
            channelnode = channel(index=self._get_next_edgeidx(), name=name, graph_ref=self, **kwargs)
167
            self.add_edge(rhash[0], rhash[1], channel_ref = channelnode)
168
        channelnode.endpoints = rrefs
169
        return channelnode
170
 
171
    def add_from_channel(self, channel_ref, router1=None, router2=None):
172
        """
173
        Add a channel object to NoC model.
174
 
175
        Use this function to add an object based on a derived class of
176
        base channel defined in this module.
177
 
178
        Arguments
179
        * channel_ref: reference to the channel object
180
        * router1: optional reference to a router, router index or ipcore
181
        * router2: -idem-
182
 
183
        Return: the same reference passed in channel_ref
184
 
185
        Notes:
186
        * If router1 or router2 are not used as arguments, will assume that
187
          channel object has defined its attribute "endpoints" with the
188
          objects to connect. If the objects don't exist in the NoC model,
189
          throw an error exception.
190
 
191
        * If router1 or router2 is an ipcore reference, this method creates
192
          the special channel object and update ipcore references. Additionally,
193
          if both arguments are ipcores, throw an error exception.
194
 
195
        * This function will change channel_ref.index and channel_ref.graph_ref
196
          attributes when inserted in the NoC model. Also it may change
197
          channel_ref.endpoints with router1 and router2 references.
198
        """
199
        if not isinstance(channel_ref, channel):
200
            raise ValueError("Argument 'channel_ref' is not a channel object.")
201
 
202
        if isinstance(router1, ipcore) and isinstance(router2, ipcore):
203
            raise ValueError("Both object references cannot be ipcore objects.")
204
 
205
        rhash = [None, None]
206
        rrefs = [None, None]
207
        for targetid, routertarget in enumerate((router1, router2)):
208
            if isinstance(routertarget, router):
209
                if routertarget.index in self.node:
210
                    rhash[targetid] = routertarget.index
211
                    rrefs[targetid] = self.node[routertarget.index]["router_ref"]
212
            elif isinstance(routertarget, ipcore):
213
                # special channel
214
                rhash[targetid] = None
215
                rrefs[targetid] = routertarget
216
            elif isinstance(routertarget, int):
217
                if routertarget in self.node:
218
                    rhash[targetid] = routertarget
219
                    rrefs[targetid] = self.node[routertarget]["router_ref"]
220
 
221
        if (router1 is None) and (router2 is None):
222
            # extract from endpoints attribute
223
            if not hasattr(channel_ref, "endpoints"):
224
                raise ValueError("Channel object has not attribute 'endpoints'")
225
            for i in range(2):
226
                if not isinstance(channel_ref.endpoints[i], [router, ipcore]):
227
                    raise ValueError("Channel object: attribute 'endpoints'[%d] is not a router or an ipcore" % i)
228
                if isinstance(channel_ref.endpoints[i], router):
229
                    if channel_ref.endpoints[i].index in self.node:
230
                        rhash[i] = channel_ref.endpoints[i].index
231
                        rrefs[i] = channel_ref.endpoints[i]
232
                if isinstance(channel_ref.endpoints[i], ipcore):
233
                    rhash[i] = None
234
                    rrefs[i] = channel_ref.endpoints[i]
235
 
236
        if rrefs[0] is None:
237
            raise ValueError("Object not found for argument 'router1'")
238
        if rrefs[1] is None:
239
            raise ValueError("Object not found for argument 'router2'")
240
 
241
        if None in rhash:
242
            ipcore_idx = rhash.index(None)
243
            channel_ref.index = None
244
            # ipcore channel: adjust the references
245
            rrefs[ipcore_idx].channel_ref = channel_ref
246
            # the other reference must be a router object
247
            rrefs[ipcore_idx - 1].ipcore_ref = rrefs[ipcore_idx]
248
        else:
249
            # inter-routers channel
250
            channel_ref.index = self._get_next_edgeidx()
251
            self.add_edge(rhash[0], rhash[1], channel_ref=channel_ref)
252
        # update common references
253
        channel_ref.graph_ref = self
254
        channel_ref.endpoints = rrefs
255
        return channel_ref
256
 
257
 
258
    def add_ipcore(self, router_ref, name="", **kwargs):
259
        """
260
        Create an ipcore object and connect it to the router reference argument
261
 
262
        Arguments
263
        * router_ref: reference to an existing router
264
        * name: optional name for this router. By default has the form of
265
          "IP_<router_index>"
266
        * kwargs: optional parameters to put as object attributes
267
 
268
        Return: reference to the created ipcore object
269
 
270
        Notes:
271
        * This function automatically adds a special channel object
272
          (router-to-ipcore) and adjust its relations in all involved objects.
273
        """
274
        if router_ref not in self.router_list():
275
            raise ValueError("Argument 'router_ref' must be an existing router.")
276
        if name == "":
277
            # channel default name format 
278
            name = "IP_%d" % router_ref.index
279
        # fix channel name, based on ipcore name
280
        chname = "CH_%s" % name
281
        newip = ipcore(name=name, router_ref=router_ref, graph_ref=self, **kwargs)
282
        channelnode = channel(index=None, name=chname, graph_ref=self, endpoints=[router_ref, newip])
283
        # fix references
284
        newip.channel_ref = channelnode
285
        router_ref.ipcore_ref = newip
286
        return newip
287
 
288
    def add_from_ipcore(self, ipcore_ref, router_ref, channel_ref=None):
289
        """
290
        Add a ipcore object to NoC model.
291
 
292
        Arguments
293
        * ipcore_ref: reference to ipcore object
294
        * router_ref: reference to an existing router to connect
295
        * channel_ref: optional channel object that connect the router and
296
          the ipcore. If not used, this function will create a new channel object.
297
 
298
        Return: the same reference passed in ipcore_ref
299
 
300
        Notes:
301
        * This function automatically adds a special channel object
302
          (router-to-ipcore) and adjust its relations in all involved objects.
303
        """
304
        if not isinstance(ipcore_ref, ipcore):
305
            raise ValueError("Argument 'ipcore_ref' is not an ipcore object.")
306
        if router_ref not in self.router_list():
307
            raise ValueError("Argument 'router_ref' must be an existing router.")
308
 
309
        if channel_ref != None:
310
            if not isinstance(channel_ref, channel):
311
                raise ValueError("Argument 'channel_ref' is not a channel object.")
312
            else:
313
                channel_ref.index = None
314
                channel_ref.graph_ref = self
315
                channel_ref.endpoints = [router_ref, ipcore_ref]
316
        else:
317
            # channel default name format 
318
            chname = "CH_IP_%d" % router_ref.index
319
            channel_ref = channel(index=None, name=chname, graph_ref=self, endpoints=[router_ref, ipcore_ref])
320
 
321
        # fix references
322
        ipcore_ref.router_ref = router_ref
323
        ipcore_ref.channel_ref = channel_ref
324
        ipcore_ref.graph_ref = self
325
        router_ref.ipcore_ref = ipcore_ref
326
 
327
        return ipcore_ref
328
 
329
    def del_router(self, router_ref):
330
        """
331
        Remove router_ref from the NoC model
332
 
333
        TODO: not implemented
334
        """
335
        pass
336
 
337
    def del_channel(self, channel_ref):
338
        """
339
        Remove channel_ref from the NoC model
340
 
341
        TODO: not implemented
342
        """
343
        pass
344
 
345
    def del_ipcore(self, ipcore_ref):
346
        """
347
        Remove ipcore_ref from the NoC model
348
 
349
        TODO: not implemented
350
        """
351
        pass
352
 
353
    # list generation functions
354
    def router_list(self):
355
        l = []
356
        for i in self.nodes_iter(data=True):
357
            l.append(i[1]["router_ref"])
358
        return l
359
 
360
    def ipcore_list(self):
361
        l = []
362
        for i in self.nodes_iter(data=True):
363
            if i[1]["router_ref"].ipcore_ref != None:
364
                l.append(i[1]["router_ref"].ipcore_ref)
365
        return l
366
 
367
    def channel_list(self):
368
        # this function does not list ipcore channels
369
        l = []
370
        for i in self.edges_iter(data=True):
371
            l.append(i[2]["channel_ref"])
372
        return l
373
 
374
    def all_list(self):
375
        l = self.router_list()
376
        l.extend(self.ipcore_list())
377
        l.extend(self.channel_list())
378
        return l
379
 
380
    # query functions
381
    def get_router_by_address(self, address):
382
        for r in self.router_list():
383
            if r.address == address:
384
                return r
385
        return False
386
 
387
    # hidden functions
388
    def _add_router_from_node(self, node, name="", router_ref=None, **kwargs):
389
        """
390
        Create a router object (or use an existing router reference) based on
391
        an existing empty node on graph object.
392
        """
393
        if router_ref is None:
394
            # index comes from node
395
            if name == "":
396
                name = "R_%d" % node
397
            routernode = router(index=node, name=name, graph_ref=self, **kwargs)
398
        else:
399
            if not isinstance(router_ref, router):
400
                raise ValueError("Argument 'router_ref' is not a router object.")
401
            routernode = router_ref
402
            routernode.index = node
403
            routernode.graph_ref = self
404
        self.node[node]["router_ref"] = routernode
405
        return routernode
406
 
407
    def _add_channel_from_edge(self, edge, name="", channel_ref=None, **kwargs):
408
        """
409
        Create a channel object (or use an existing channel reference) based
410
        on an existing edge on graph object.
411
        """
412
        # inter-routers channels only
413
        rrefs = [self.node[edge[0]]["router_ref"], self.node[edge[1]]["router_ref"]]
414
        chindex = self.edges().index(edge)
415
        if channel_ref is None:
416
            if name == "":
417
                # channel default name format 
418
                name = "CH_%s:%s" % (rrefs[0].name, rrefs[1].name)
419
            channelnode = channel(index=chindex, name=name, graph_ref=self, **kwargs)
420
        else:
421
            if not isinstance(channel_ref, channel):
422
                raise ValueError("Argument 'channel_ref' is not a channel object.")
423
            channelnode = channel_ref
424
            channelnode.index = chindex
425
            channelnode.graph_ref = self
426
        channelnode.endpoints = rrefs
427
        self.get_edge_data(edge[0], edge[1])["channel_ref"] = channelnode
428
 
429
        return channelnode
430
 
431
    def _get_next_nodeidx(self):
432
        # get the next node index number
433
        # don't use intermediate available indexes
434
        return len(self.nodes())
435
 
436
    def _get_next_edgeidx(self):
437
        # get the next edge index number
438
        # don't use intermediate available indexes
439
        return len(self.edges())
440
 
441
# *******************************
442
# Generic models for NoC elements
443
# *******************************
444
 
445
class nocobject():
446
    """
447
    NoC base object
448
 
449
    This base class is used to implement common methods for NoC objects.
450
    Don't use directly.
451
    """
452
    def get_protocol_ref(self):
453
        """
454
        Get protocol object for this instance
455
        """
456
        if hasattr(self, "protocol_ref"):
457
            if isinstance(self.protocol_ref, protocol):
458
                return self.protocol_ref
459
        if isinstance(self.graph_ref.protocol_ref, protocol):
460
            return self.graph_ref.protocol_ref
461
        # nothing?
462
        return None
463
 
464
class ipcore(nocobject):
465
    """
466
    IP core base object
467
 
468
    This object represents a IP Core object and its properties. This base class
469
    is meant to either be inherited or extended by adding other attributes.
470
 
471
    Relations with other objects:
472
    * It should be related to one NoC model object (self.graph_ref)
473
    * It should have one reference to a router object (self.router_ref), even if
474
      the ipcore has a direct connection to the NoC.
475
    * It should have one reference to a channel object (self.channel_ref). This
476
      channel exclusively link this ipcore and its router.
477
 
478
    Attributes:
479
    * name
480
    * router_ref: optional reference to its related router.
481
    * channel_ref: optional reference to its related channel
482
    * graph_ref: optional reference to its graph model
483
    """
484
    def __init__(self, name, **kwargs):
485
        # Basic properties
486
        self.name = name
487
        # default values
488
        self.router_ref = None
489
        self.channel_ref = None
490
        self.graph_ref = None
491
        for key in kwargs.keys():
492
            setattr(self, key, kwargs[key])
493
 
494
class router(nocobject):
495
    """
496
    Router base object
497
 
498
    This object represents a router object and its properties. This base class
499
    is meant to either be inherited or extended by adding other attributes.
500
 
501
    Relations with other objects:
502
    * It should be related to one NoC model object (self.graph_ref)
503
    * It should be one of the node attributes in the graph model
504
      (node["router_ref"])
505
    * It may have one reference to an ipcore object (self.ipcore_ref)
506
    * It has a port list with relations to other routers through channel objects,
507
      and only one relation to its ipcore object through one channel.
508
      (self.ports). Note that this attribute must be updated after changing
509
      the NoC model.
510
 
511
    Attributes:
512
    * index: index on a noc object. Essential to search for a router object
513
    * name
514
    * ipcore_ref: optional reference to its related ipcore
515
    * graph_ref: optional reference to its graph model
516
    """
517
    def __init__(self, index, name, **kwargs):
518
        # Basic properties
519
        self.index = index
520
        self.name = name
521
        # default values
522
        self.ipcore_ref = None
523
        self.graph_ref = None
524
        # address can be anything, but let use index by default
525
        # note that address can be overriden with optional arguments in kwargs
526
        self.address = index
527
        for key in kwargs.keys():
528
            setattr(self, key, kwargs[key])
529
        # ports structure
530
        self.ports = {}
531
        # available routes info
532
        self.routes_info = {}
533
 
534
    # update functions: call them when the underlying NoC structure
535
    # has changed
536
    def update_ports_info(self):
537
        """
538
        Update the dictionary "ports": information about router neighbors,
539
        the channels that connect them and its references.
540
 
541
        Ports dictionary has the following structure:
542
        * key: address of the neighbor router that this port connects.
543
        * value: dictionary with the following keys:
544
            * "peer" (required): reference to the neighbor router
545
            * "channel" (required): reference to the channel that connects this
546
              router and its neighbor router.
547
            * Optional keys can be added to this dictionary.
548
        * Also, the special key "local address" holds the port to
549
          router's ipcore. Its values are:
550
            * "peer" (required): reference to its ipcore
551
            * "channel" (required): reference to the channel that connects this
552
              router and its ipcore.
553
            * Optional keys can be added to this dictionary with the same
554
              meaning as other ports.
555
        """
556
        # port definitions
557
        localhash = self.address
558
        updated_addr = [self.address]
559
        for neighborhash in self.graph_ref.neighbors(localhash):
560
            neighbor = self.graph_ref.node[neighborhash]["router_ref"]
561
            #check if already defined in ports dictionary
562
            if neighbor.address not in self.ports:
563
                self.ports[neighbor.address] = {}
564
            # update relevant data
565
            self.ports[neighbor.address]["peer"] = neighbor
566
            ch_ref = self.graph_ref.edge[localhash][neighborhash]["channel_ref"]
567
            self.ports[neighbor.address]["channel"] = ch_ref
568
            updated_addr.append(neighbor.address)
569
 
570
        # special port: ipcore
571
        if self.address not in self.ports:
572
            self.ports[self.address] = {}
573
        self.ports[self.address]["peer"] = self.ipcore_ref
574
        # take channel reference from ipcore. Other channels are related to
575
        # an edge on the graph model. Channels in an ipcore are special because
576
        # they don't have a related edge, just link an ipcore and this router
577
        self.ports[self.address]["channel"] = self.ipcore_ref.channel_ref
578
 
579
        # clean 'deleted' ports
580
        keys = self.ports.iterkeys()
581
        for deleted in keys:
582
            if deleted not in updated_addr:
583
                del self.ports[deleted]
584
 
585
    def update_routes_info(self):
586
        """
587
        Update the dictionary "routes_info": it is a table with information
588
        about how a package, starting from this router, can reach another one.
589
 
590
        routes_info dictionary has the following structure:
591
        * keys : the address of all the routers in NoC
592
        * values : an ordered list of dictionaries with
593
            * "next" : address of the next router
594
            * "paths" : list of possible paths for key destination
595
 
596
        """
597
        # this function will calculate a new table!
598
        self.routes_info.clear()
599
 
600
        #mynodehash = (self.coord_x, self.coord_y)
601
        mynodehash = self.index
602
 
603
        for destrouter in self.graph_ref.router_list():
604
            # discard route to myself
605
            if destrouter == self:
606
                continue
607
            #desthash = (destrouter.coord_x, destrouter.coord_y)
608
            desthash = destrouter.index
609
 
610
            # entry for destrouter
611
            self.routes_info[destrouter.index] = []
612
 
613
            # first: take all shortest paths (function not available on NetworkX)
614
            shortest_routes = all_shortest_paths(self.graph_ref, mynodehash, desthash)
615
            # convert nodehashes to router addresses
616
            shortest_r_addr = [map(lambda x : self.graph_ref.node[x]["router_ref"].address, i) for i in shortest_routes]
617
 
618
            # NOTE about routing tables: need to think about which routes based on 
619
            # shortest paths are better in general with other routers, so the links
620
            # are well balanced. A possible problem could be that some links will carry
621
            # more data flow than others.
622
            # A possible workaround lies in the generation of routing tables at
623
            # NoC level, taking account of neighbors tables and others parameters.
624
 
625
            # extract the next neighbor in each path
626
            for route in shortest_r_addr:
627
                # first element is myself, last element is its destination. 
628
                # for this routing table, we only need the next router to
629
                # send the package.
630
                newroute = True
631
                for route_entry in self.routes_info[destrouter.index]:
632
                    if route[1] == route_entry["next"]:
633
                        # another route which next element was taken account
634
                        route_entry["paths"].append(route)
635
                        newroute = False
636
                if newroute:
637
                    self.routes_info[destrouter.index].append({"next": route[1], "paths": [route]})
638
            # last option: send through another node not in the shortest paths 
639
            # NOTE: decide if this is needed or make sense
640
 
641
class channel(nocobject):
642
    """
643
    Channel base object
644
 
645
    This object represents a channel object and its properties. This base class
646
    is meant to either be inherited or extended by adding other attributes.
647
 
648
    Relations with other objects:
649
    * It should be related to one NoC model object (self.graph_ref)
650
    * It may be one of the edge attributes in the graph model
651
      (edge["channel_ref"]). In this case, this channel connects two routers
652
      in the NoC model.
653
    * It should have two references to NoC objects (self.endpoints). Two options
654
      exists: two routers references (channel has an edge object) or, one
655
      router and one ipcore (channel don't have any edge object).
656
 
657
    Attributes:
658
    * name
659
    * index: optional index on a noc object. Must have an index when it has
660
      a related edge in the graph model (and allowing it to be able to do
661
      channel searching). None means it is an ipcore related channel
662
    * graph_ref optional reference to its graph model
663
    * endpoints optional two-item list with references to the connected objects
664
    """
665
    def __init__(self, name, index=None, **kwargs):
666
        # Basic properties
667
        self.index = index
668
        self.name = name
669
        # Default values
670
        self.graph_ref = None
671
        self.endpoints = [None, None]
672
        for key in kwargs.keys():
673
            setattr(self, key, kwargs[key])
674
 
675
    def is_ipcore_link(self):
676
        """
677
        Checks if this channel is a special link for an ipcore.
678
 
679
        Return: True if the channel is related to an ipcore
680
        """
681
        # Search for ipcore in endpoints. Don't check None on self.index.
682
        for ref in self.endpoints:
683
            if isinstance(ref, ipcore):
684
                return True
685
        return False
686
 
687
class protocol(nocobject):
688
    """
689
    Protocol base object
690
 
691
    This object represents the protocol that the NoC objects use. This
692
    object has attributes that define the protocol used, mainly it can be
693
    used to generate, encode, decode or interpret packets on the NoC.
694
    This base class can be either be inherited or extended by adding
695
    other attributes.
696
 
697
    Relations with other objects:
698
    * Each object on the NoC (routers, channels and ipcores) may have
699
      one reference to a protocol object (object.protocol_ref)
700
    * A NoC model may have a protocol object: in this case, all objects in
701
      the model will use this protocol (nocmodel.protocol_ref)
702
    * A protocol object is a generator of packet objects
703
 
704
    Attributes:
705
    * name
706
 
707
    Notes:
708
    * Optional arguments "packet_format" and "packet_order" can be
709
      added at object construction, but will not check its data consistency.
710
      At the moment, we recommend using update_packet_field() method to
711
      fill this data structures.
712
    """
713
    def __init__(self, name="", **kwargs):
714
        """
715
        Constructor
716
 
717
        Notes:
718
        * Optional arguments will be added as object attributes.
719
        """
720
        # NOTE: to avoid python version requirements (2.7), implement ordered 
721
        # dict with an additional list. When we are sure of using 
722
        # Python > 2.7 , change to collections.OrderedDict
723
        self.name = name
724
        self.packet_format = {}
725
        self.packet_order = []
726
        self.packet_class = packet
727
        for key in kwargs.keys():
728
            setattr(self, key, kwargs[key])
729
 
730
    def get_protocol_ref(self):
731
        # override to use myself
732
        return self
733
 
734
    def update_packet_field(self, name, type, bitlen, description=""):
735
        """
736
        Add or update a packet field.
737
 
738
        Arguments
739
        * name
740
        * type: string that can be "int", "fixed" or "float"
741
        * bitlen: bit length of this field
742
        * description: optional description of this field
743
 
744
        Notes:
745
        * Each new field will be added at the end.
746
        """
747
        if (type != "int") and (type != "fixed") and (type != "float"):
748
            raise ValueError("Argument 'type' must be 'int', 'fixed' or 'float'.")
749
 
750
        if name in self.packet_format:
751
            # update field
752
            previdx = self.packet_order.index(name) - 1
753
            if previdx < 0:
754
                # first field
755
                lastbitpos = 0
756
            else:
757
                lastbitpos = self.packet_format[self.packet_order[previdx]][lsb]
758
            nextbitpos = lastbitpos + bitlen
759
            self.packet_format[name]["type"] = type
760
            self.packet_format[name]["position"] = previdx + 1
761
            # check if the packet format needs to adjust the bit positions
762
            if self.packet_format[name]["bitlen"] != bitlen:
763
                self.packet_format[name]["bitlen"] = bitlen
764
                self.packet_format[name]["lsb"] = nextbitpos
765
                self.packet_format[name]["msb"] = lastbitpos
766
                # iterate through the rest of the fields adjusting lsb and msb
767
                for idx in range(previdx+2, len(self.packet_order)):
768
                    curname = self.packet_order[idx]
769
                    curbitlen = self.packet_format[curname]["bitlen"]
770
                    self.packet_format[curname]["lsb"] = nextbitpos + curbitlen
771
                    self.packet_format[curname]["msb"] = nextbitpos
772
                    nextbitpos += curbitlen
773
        else:
774
            # append
775
            if len(self.packet_format) == 0:
776
                lastbitpos = 0
777
            else:
778
                lastbitpos = self.packet_format[self.packet_order[-1]]["lsb"]
779
            nextbitpos = lastbitpos + bitlen
780
            fieldpos = len(self.packet_order)
781
            self.packet_format[name] = {"type": type, "position": fieldpos, "bitlen": bitlen, "lsb": nextbitpos, "msb": lastbitpos}
782
            self.packet_order.append(name)
783
 
784
    def newpacket(self, zerodefault=True, *args, **kwargs):
785
        """
786
        Return a new packet with all required fields.
787
 
788
        Arguments:
789
        * zerodefault: If True, all missing fields will be zeroed by default.
790
          If False, a missing value in arguments will throw an exception.
791
        * args: Nameless arguments will add field values based on packet field
792
          order.
793
        * kwargs: Key-based arguments will add specified field values based in
794
          its keys
795
 
796
        Notes:
797
        * kwargs takes precedence over args: i.e. named arguments can overwrite
798
          nameless arguments.
799
        """
800
        retpacket = self.packet_class(protocol_ref=self)
801
        fieldlist = self.packet_order[:]
802
        # first named arguments
803
        for fkey, fvalue in kwargs.iteritems():
804
            if fkey in fieldlist:
805
                retpacket[fkey] = fvalue
806
                fieldlist.remove(fkey)
807
        # then nameless
808
        for fidx, fvalue in enumerate(args):
809
            fkey = self.packet_order[fidx]
810
            if fkey in fieldlist:
811
                retpacket[fkey] = fvalue
812
                fieldlist.remove(fkey)
813
        # check for empty fields
814
        if len(fieldlist) > 0:
815
            if zerodefault:
816
                for fkey in fieldlist:
817
                    retpacket[fkey] = 0
818
            else:
819
                raise ValueError("Missing fields in argument list: %s" % repr(fieldlist))
820
        return retpacket
821
    def register_packet_generator(self, packet_class):
822
        """
823
        Register a special packet generator class.
824
 
825
        Must be a derived class of packet
826
        """
827
        if not issubclass(packet_class, packet):
828
            raise TypeError("Argument 'packet_class' must derive from 'packet' class.")
829
        self.packet_class = packet_class
830
 
831
class packet(dict):
832
    """
833
    Packet base object
834
 
835
    This object represents a packet data, related to a protocol object. It
836
    behaves exactly like a Python dictionary, but adds methods to simplify
837
    packet transformations.
838
 
839
    Relations with other objects:
840
    * It should be generated by a protocol object (and will have a reference
841
      in self.protocol_ref)
842
 
843
    Attributes:
844
    * protocol_ref: protocol object that created this object.
845
    """
846
 
847
    # the constructor 
848
    def __init__(self, *args, **kwargs):
849
        # look for a protocol_ref key
850
        self.protocol_ref = kwargs.pop("protocol_ref", None)
851
        dict.__init__(self, *args, **kwargs)
852
 
853
# *******************************
854
# Additional functions
855
# *******************************
856
 
857
# Missing function in NetworkX
858
def all_shortest_paths(G,a,b):
859
    """
860
    Return a list of all shortest paths in graph G between nodes a and b
861
    This is a function not available in NetworkX (checked at 22-02-2011)
862
 
863
    Taken from:
864
    http://groups.google.com/group/networkx-discuss/browse_thread/thread/55465e6bb9bae12e
865
    """
866
    ret = []
867
    pred = nx.predecessor(G,b)
868
    if not pred.has_key(a):  # b is not reachable from a
869
        return []
870
    pth = [[a,0]]
871
    pthlength = 1  # instead of array shortening and appending, which are relatively
872
    ind = 0        # slow operations, we will just overwrite array elements at position ind
873
    while ind >= 0:
874
        n,i = pth[ind]
875
        if n == b:
876
            ret.append(map(lambda x:x[0],pth[:ind+1]))
877
        if len(pred[n]) > i:
878
            ind += 1
879
            if ind == pthlength:
880
                pth.append([pred[n][i],0])
881
                pthlength += 1
882
            else:
883
                pth[ind] = [pred[n][i],0]
884
        else:
885
            ind -= 1
886
            if ind >= 0:
887
                pth[ind][1] += 1
888
    return ret

powered by: WebSVN 2.1.0

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