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

Subversion Repositories nocmodel

[/] [nocmodel/] [trunk/] [nocmodel/] [basicmodels/] [basic_router.py] - Blame information for rev 4

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
# Basic Router model
6 4 dargor
#  * TBM model
7
#  * Code generation model
8 2 dargor
#
9
# Author:  Oscar Diaz
10 4 dargor
# Version: 0.2
11
# Date:    14-03-2011
12 2 dargor
 
13
#
14
# This code is free software; you can redistribute it and/or
15
# modify it under the terms of the GNU Lesser General Public
16
# License as published by the Free Software Foundation; either
17
# version 2.1 of the License, or (at your option) any later version.
18
#
19
# This code is distributed in the hope that it will be useful,
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22
# Lesser General Public License for more details.
23
#
24
# You should have received a copy of the GNU Lesser General Public
25
# License along with this library; if not, write to the
26
# Free Software  Foundation, Inc., 59 Temple Place, Suite 330,
27
# Boston, MA  02111-1307  USA
28
#
29
 
30
#
31
# Changelog:
32
#
33
# 03-03-2011 : (OD) initial release
34 4 dargor
# 14-03-2011 : (OD) adding code generation model
35 2 dargor
#
36
 
37
"""
38 4 dargor
* Basic router TBM model
39
* Router code generation model
40 2 dargor
"""
41
 
42 4 dargor
from nocmodel.noc_tbm_base import *
43
from nocmodel.noc_codegen_base import *
44
from intercon_model import *
45 2 dargor
 
46
# ---------------------------
47 4 dargor
# Router TBM model
48 2 dargor
 
49 4 dargor
class basic_router_tbm(noc_tbm_base):
50 2 dargor
    """
51 4 dargor
    TBM model of a NoC router. This router uses store-and-forward technique,
52 2 dargor
    using the routing information from the router object. This model just
53
    forward the packet, and if the packet is in its router destination, send it
54
    to its ipcore. Each package that the ipcore generates is delivered
55
    automátically.
56
 
57
    Attributes:
58
    * router_ref : base reference
59
    * fifo_len: max number of packets to hold in each port
60
 
61
    Notes:
62
    * This model is completely behavioral.
63
    * See code comments to better understanding.
64
    """
65 4 dargor
    def __init__(self, router_ref, fifo_len=5):
66
        noc_tbm_base.__init__(self)
67 2 dargor
        if isinstance(router_ref, router):
68
            self.router_ref = router_ref
69
            self.graph_ref = router_ref.graph_ref
70
            self.logname = "Router '%s'" % router_ref.name
71
            if router_ref.name == "":
72
                self.logname = "Router addr '%s'" % router_ref.address
73
        else:
74
            raise TypeError("This class needs a router object as constructor argument.")
75
 
76
        self.debug("constructor")
77
 
78
        # generic parameters
79
        self.fifo_len = fifo_len
80
 
81
        # delay parameters
82
        self.delay_route = 5        # delay for each routing decisition
83
        self.delay_outfromfifo = 2  # delay for extract packet from fifo to output port
84
        self.delay_ipcorebus = 1    # delay for ipcore local bus operations
85
 
86
        # router parameters (Assume rectangular coords)
87
        self.myaddress = router_ref.address
88
        self.mynodecoord = (router_ref.coord_x, router_ref.coord_y)
89
 
90
        # port additions: use a copy of the ports list, and add
91
        # fifo storage and signal events
92
        router_ref.update_ports_info()
93
        self.ports_info = router_ref.ports.copy()
94
        for p in self.ports_info.itervalues():
95
            p["fifo_in"] = []
96
            p["fifo_out"] = []
97
            p["fifo_in_event"] = myhdl.Signal(False)
98
            p["fifo_out_event"] = myhdl.Signal(False)
99 4 dargor
        self.idlesignal = myhdl.Signal(True)
100 2 dargor
 
101
        # extract a list of all fifo event signals
102
        self.list_fifo_in_events = [i["fifo_in_event"] for i in self.ports_info.itervalues()]
103
        self.list_fifo_out_events = [i["fifo_out_event"] for i in self.ports_info.itervalues()]
104
 
105
        # the routing table is generated from the routes_info dict
106
        # key: its destination address
107
        # values: a list of ports where the package should send it. First element
108
        #    is the default option, next elements are alternate routes
109
        router_ref.update_routes_info()
110
        self.detailed_routingtable = self.router_ref.routes_info.copy()
111
        self.routingtable = {}
112
        for dest, data in self.detailed_routingtable.iteritems():
113
            self.routingtable[dest] = [x["next"] for x in data]
114
        # add route to myself
115
        self.routingtable[self.myaddress] = [self.myaddress]
116
 
117
        # log interesting info
118
        self.info(" router params: fifo_len=%d" % self.fifo_len)
119
        self.info(" router info: addr=%d coord=%s" % (self.myaddress, repr(self.mynodecoord)))
120
        self.info(" router ports: %s" % repr(self.ports_info))
121
        self.info(" router routing table: %s" % repr(self.routingtable))
122
 
123
        # myhdl generators (concurrent processes)
124
        self.generators = []
125
 
126
        # fifo out process
127
        @myhdl.instance
128
        def flush_fifo_out():
129
            while True:
130
                for port, data in self.ports_info.iteritems():
131
                    if len(data["fifo_out"]) > 0:
132 4 dargor
                        self.idlesignal.next = False
133 2 dargor
                        if not data["fifo_out_event"].val:
134
                            self.debug("flush_fifo_out CATCH fifo not empty and NO trigger! fifo has %s" % repr(data["fifo_out"]))
135
                        self.info("flush_fifo_out event in port %d" % port)
136
                        packet = data["fifo_out"].pop(0)
137
                        self.debug("flush_fifo_out port %d packet is %s (delay %d)" % (port, repr(packet), self.delay_outfromfifo))
138
                        # DELAY model: time to move from fifo to external port in destination object
139
                        yield myhdl.delay(self.delay_outfromfifo)
140 4 dargor
                        self.idlesignal.next = False
141 2 dargor
                        # try to send it
142
                        retval = self.send(self.router_ref, data["channel"], packet)
143 4 dargor
                        if retval == noc_tbm_errcodes.no_error:
144 2 dargor
                            # clean trigger
145
                            data["fifo_out_event"].next = False
146 4 dargor
                            self.debug("flush_fifo_out clean trigger. list %s" % repr(self.list_fifo_out_events))
147 2 dargor
                            #continue
148
                        else:
149
                            self.error("flush_fifo_out FAILED in port %d (code %d)" % (port, retval))
150
                            # error management: 
151
                            #TODO: temporally put back to fifo
152
                            self.info("flush_fifo_out packet went back to fifo.")
153
                            data["fifo_out"].append(packet)
154 4 dargor
                    else:
155
                        if data["fifo_out_event"].val:
156
                            self.debug("flush_fifo_out CATCH fifo_out empty and trigger ON! Cleaning trigger")
157
                            data["fifo_out_event"].next = False
158
                self.idlesignal.next = True
159 2 dargor
                yield self.list_fifo_out_events
160
                self.debug("flush_fifo_out event hit. list %s" % repr(self.list_fifo_out_events))
161
 
162
        # routing loop
163
        @myhdl.instance
164
        def routing_loop():
165
            while True:
166
                # routing update: check all fifos
167
                for port, data in self.ports_info.iteritems():
168
                    while len(data["fifo_in"]) > 0:
169 4 dargor
                        self.idlesignal.next = False
170 2 dargor
                        if not data["fifo_in_event"].val:
171
                            self.debug("routing_loop CATCH fifo not empty and NO trigger! fifo has %s" % repr(data["fifo_in"]))
172
                        self.info("routing_loop fifo_in event in port %d" % port)
173
                        # data in fifo
174
                        packet = data["fifo_in"].pop(0)
175
                        data["fifo_in_event"].next = False
176
                        self.debug("routing_loop port %d packet %s to ipcore (delay %d)" % (port, repr(packet), self.delay_route))
177
                        # destination needed. extract from routing table
178
                        destaddr = packet["dst"]
179
                        self.debug("routing_loop port %d routingtable %s (dest %d)" % (port, repr(self.routingtable), destaddr))
180
                        nextaddr = self.routingtable[destaddr][0]
181
                        self.debug("routing_loop port %d to port %s (dest %d)" % (port, nextaddr, destaddr))
182
                        # DELAY model: time spent to make a route decisition
183
                        yield myhdl.delay(self.delay_route)
184 4 dargor
                        self.idlesignal.next = False
185 2 dargor
                        self.ports_info[nextaddr]["fifo_out"].append(packet)
186
                        # fifo trigger
187
                        if self.ports_info[nextaddr]["fifo_out_event"]:
188
                            self.debug("routing_loop CATCH possible miss event because port %d fifo_out_event=True", self.myaddress)
189
                        self.ports_info[nextaddr]["fifo_out_event"].next = True
190 4 dargor
                    # assuming empty fifo_in
191
                    if data["fifo_in_event"].val:
192
                        self.debug("routing_loop CATCH fifo_in empty and trigger ON! Cleaning trigger")
193
                        data["fifo_in_event"].next = False
194
                self.idlesignal.next = True
195
                self.debug("routing_loop idle. fifo_in_events list %s" % repr(self.list_fifo_in_events))
196
                if not any(self.list_fifo_in_events):
197
                    yield self.list_fifo_in_events
198
                else:
199
                    self.debug("routing_loop pending fifo_in_events list %s" % repr(self.list_fifo_in_events))
200
                self.debug("routing_loop fifo_in event hit. list %s" % repr(self.list_fifo_in_events))
201 2 dargor
 
202
        # list of all generators
203
        self.generators.extend([flush_fifo_out, routing_loop])
204
        self.debugstate()
205
 
206
    # Transaction - related methods
207
    def send(self, src, dest, packet, addattrs=None):
208
        """
209
        This method will be called on a fifo available data event
210
 
211
        Notes:
212
        * Ignore src object.
213
        * dest should be a channel object, but also can be a router address or
214
          a router object.
215
        """
216
        self.debug("-> send( %s , %s , %s , %s )" % (repr(src), repr(dest), repr(packet), repr(addattrs)))
217
        if isinstance(dest, int):
218
            # it means dest is a router address
219
            therouter = self.graph_ref.get_router_by_address(dest)
220
            if therouter == False:
221
                self.error("-> send: dest %s not found" % repr(dest) )
222 4 dargor
                return noc_tbm_errcodes.tbm_badcall_send
223 2 dargor
            # extract channel ref from ports_info
224
            thedest = self.ports_info[therouter.address]["channel"]
225
        elif isinstance(dest, router):
226
            # extract channel ref from ports_info
227
            thedest = self.ports_info[dest.address]["channel"]
228
        elif isinstance(dest, channel):
229
            # use it directly
230
            thedest = dest
231
        else:
232
            self.error("-> send: what is dest '%s'?" % repr(dest) )
233 4 dargor
            return noc_tbm_errcodes.tbm_badcall_send
234 2 dargor
 
235
        # call recv on the dest channel object
236 4 dargor
        retval = thedest.tbm.recv(self.router_ref, thedest, packet, addattrs)
237 2 dargor
 
238
        # TODO: something to do with the retval?
239
        self.debug("-> send returns code '%s'" % repr(retval))
240
        return retval
241
 
242
    def recv(self, src, dest, packet, addattrs=None):
243
        """
244
        This method will be called by channel objects connected to this router.
245
 
246
        Notes:
247
        * The recv method only affect the receiver FIFO sets
248
        * Ignore dest object.
249
        """
250
 
251
        self.debug("-> recv( %s , %s , %s , %s )" % (repr(src), repr(dest), repr(packet), repr(addattrs)))
252
        # src can be an address or a noc object.
253
        # convert to addresses
254
        if isinstance(src, int):
255
            thesrc = src
256
        elif isinstance(src, router):
257
            thesrc = src.address
258
        elif isinstance(src, channel):
259
            # get address from the other end. Use the endpoints to calculate
260
            # source router
261
            src_index = src.endpoints.index(self.router_ref) - 1
262
            theend = src.endpoints[src_index]
263
            if isinstance(theend, router):
264
                thesrc = theend.address
265
            elif isinstance(theend, ipcore):
266
                thesrc = theend.router_ref.address
267
            else:
268
                self.error("-> recv: what is endpoint '%s' in channel '%s'?" % (repr(theend), repr(src)) )
269 4 dargor
                return noc_tbm_errcodes.tbm_badcall_recv
270 2 dargor
        else:
271
            self.error("-> recv: what is src '%s'?" % repr(src) )
272 4 dargor
            return noc_tbm_errcodes.tbm_badcall_recv
273 2 dargor
 
274
        # thesrc becomes the port number
275
        # check if there is enough space on the FIFO
276
        if len(self.ports_info[thesrc]["fifo_in"]) == self.fifo_len:
277
            # full FIFO
278
            self.error("-> recv: full fifo. Try later.")
279 4 dargor
            self.debug("-> recv: port %s fifo_in contents: %s" % (thesrc, repr(self.ports_info[thesrc]["fifo_in"])))
280
            return noc_tbm_errcodes.full_fifo
281 2 dargor
        # get into fifo
282
        self.ports_info[thesrc]["fifo_in"].append(packet)
283
        # trigger a new routing event
284
        if self.ports_info[thesrc]["fifo_in_event"].val:
285
            self.debug("-> recv: CATCH possible miss event because in port %d fifo_in_event=True", thesrc)
286 4 dargor
            self.debug("-> recv: CATCH fifo_in_event list %s" % repr(self.list_fifo_in_events))
287 2 dargor
        self.ports_info[thesrc]["fifo_in_event"].next = True
288
 
289 4 dargor
        self.debug("-> recv returns 'noc_tbm_errcodes.no_error'")
290
        return noc_tbm_errcodes.no_error
291
 
292
# ---------------------------
293
# Router code generation model
294
 
295
class basic_router_codegen(noc_codegen_ext):
296
    """
297
    Code generation extension for Router objects.
298
    """
299
 
300
    def __init__(self, codegen_ref):
301
        noc_codegen_ext.__init__(self, codegen_ref)
302
        self.router_ref = codegen_ref.nocobject_ref
303
        if not isinstance(self.router_ref, router):
304
            raise TypeError("Argument must be a 'noc_codegen_base' instance defined for a router object.")
305
 
306
        # router model: This basic router has some parameters put in the 
307
        # generics list, and a fixed number of NoC ports: 4. 
308
 
309
        # assumptions: use 4 ports 'dualwb_intercon' plus 1 port 'slavewb_intercon'
310
 
311
        codegen_ref.modulename = "basic_4P_router"
312
 
313
        # 1. convert basic attributes to generics
314
        codegen_ref.add_generic("name", self.router_ref.name, "Router Name")
315
        codegen_ref.add_generic("address", self.router_ref.address, "Router Address")
316
        # assuming rectangular layout
317
        codegen_ref.add_generic("coord_x", self.router_ref.coord_x, "Router X-axis Coord")
318
        codegen_ref.add_generic("coord_y", self.router_ref.coord_y, "Router Y-axis Coord")
319
 
320
        # 2. Calculate which of 4 ports is used by who
321
        portinfo = {"N": None, "E": None, "S": None, "W": None}
322
        for pname, pvalues in self.router_ref.ports.iteritems():
323
            if pname != self.router_ref.address:
324
                # check correct intercon
325
                if not isinstance(pvalues["channel"].ports[self.router_ref.address]["intercon"], dualwb_intercon):
326
                    raise UserWarning("Port '%d' on router '%s' does not use intercon 'dualwb_intercon'." % (pname, self.router_ref.name))
327
                # calculate which port
328
                dx = self.router_ref.coord_x - pvalues["peer"].coord_x
329
                dy = self.router_ref.coord_y - pvalues["peer"].coord_y
330
                if dx == 0:
331
                    if dy > 0:
332
                        portinfo["S"] = pname
333
                    else:
334
                        portinfo["N"] = pname
335
                if dy == 0:
336
                    if dx > 0:
337
                        portinfo["W"] = pname
338
                    else:
339
                        portinfo["E"] = pname
340
            else:
341
                # check correct intercon
342
                if not isinstance(pvalues["channel"].ports[self.router_ref.address]["intercon"], slavewb_intercon):
343
                    raise UserWarning("Port 'Local' on router '%s' does not use intercon 'slavewb_intercon'." % self.router_ref.name)
344
 
345
        icon_ref = dualwb_intercon()
346
        # 3. Add ports and info through generics
347
        for pname, pvalue in portinfo.iteritems():
348
            # add new port
349
            pstr = "Port%s" % pname
350
            codegen_ref.add_port(pstr, None, "Port %s" % pname, type=icon_ref.intercon_type, nocport=pvalue)
351
            for signame, sigval in icon_ref.signals.iteritems():
352
                stmp = get_new_signal(
353
                    name=signame,
354
                    direction=sigval["direction"],
355
                    default_value=intbv(0)[sigval["width"]:],
356
                    description=sigval["description"])
357
                codegen_ref.add_port(pstr, stmp)
358
            # determine if the port is used
359
            if pvalue is None:
360
                penable = 0
361
                paddr = 0
362
            else:
363
                penable = 1
364
                paddr = pvalue
365
            codegen_ref.add_generic("Use_Port%s" % pname, penable, "Is Port%s being used?" % pname)
366
            codegen_ref.add_generic("Dest_Port%s" % pname, paddr, "Dest address in Port%s" % pname)
367
        # 4. Local port
368
        icon_ref = slavewb_intercon()
369
        codegen_ref.add_port("PortLocal", None, "Port Local", type=icon_ref.intercon_type)
370
        for signame, sigval in icon_ref.signals.iteritems():
371
            stmp = get_new_signal(
372
                name=signame,
373
                direction=sigval["direction"],
374
                default_value=intbv(0)[sigval["width"]:],
375
                description=sigval["description"])
376
            codegen_ref.add_port("PortLocal", stmp)
377
 
378
        # 5. Calculate a hash with generics and ports info. This hash will help 
379
        # codegen to establish equivalent router implementations.
380
        codegen_ref.model_hash()
381
 
382
        # 6. Implementation comment
383
        codegen_ref.implementation += "-- Add here implementation code for Router %s" % self.router_ref.name

powered by: WebSVN 2.1.0

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