| 1 |
2 |
dargor |
#!/usr/bin/env python
|
| 2 |
|
|
# -*- coding: utf-8 -*-
|
| 3 |
|
|
|
| 4 |
|
|
#
|
| 5 |
|
|
# Basic IPcore 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 ipcore TBM model
|
| 39 |
|
|
* Ipcore 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 |
# Basic IPCore TBM model
|
| 48 |
2 |
dargor |
|
| 49 |
4 |
dargor |
class basic_ipcore_tbm(noc_tbm_base):
|
| 50 |
2 |
dargor |
"""
|
| 51 |
4 |
dargor |
TBM model of a NoC ipcore. Its based on sending and receiving packets
|
| 52 |
2 |
dargor |
to a custom-based MyHDL generators. This class does not define any
|
| 53 |
|
|
functionality.
|
| 54 |
|
|
|
| 55 |
|
|
Attributes:
|
| 56 |
|
|
* ipcore_ref: reference to ipcore base object
|
| 57 |
|
|
|
| 58 |
|
|
Notes:
|
| 59 |
|
|
* This model is completely behavioral.
|
| 60 |
|
|
* See code comments to better understanding.
|
| 61 |
|
|
"""
|
| 62 |
|
|
def __init__(self, ipcore_ref):
|
| 63 |
4 |
dargor |
noc_tbm_base.__init__(self)
|
| 64 |
2 |
dargor |
if isinstance(ipcore_ref, ipcore):
|
| 65 |
|
|
self.ipcore_ref = ipcore_ref
|
| 66 |
|
|
self.graph_ref = ipcore_ref.graph_ref
|
| 67 |
|
|
self.logname = "IPCore '%s'" % ipcore_ref.name
|
| 68 |
|
|
if ipcore_ref.name == "":
|
| 69 |
|
|
self.logname = "IPCore '%s'" % ipcore_ref.router_ref.name
|
| 70 |
|
|
else:
|
| 71 |
|
|
raise TypeError("This class needs a ipcore object as constructor argument.")
|
| 72 |
|
|
|
| 73 |
|
|
self.debug("constructor")
|
| 74 |
|
|
# generic parameters
|
| 75 |
4 |
dargor |
self.retrytimes = 3
|
| 76 |
|
|
self.retrydelay = 2
|
| 77 |
2 |
dargor |
|
| 78 |
|
|
# one-port support: get a reference to the related channel
|
| 79 |
|
|
self.localch = self.ipcore_ref.channel_ref
|
| 80 |
|
|
|
| 81 |
|
|
# get protocol reference
|
| 82 |
|
|
self.protocol_ref = self.ipcore_ref.get_protocol_ref()
|
| 83 |
|
|
|
| 84 |
|
|
# bidirectional port: the sender part will write data to the signal
|
| 85 |
|
|
# outgoing_packet. This class provides a generator thar call send()
|
| 86 |
|
|
# method when there is new data.
|
| 87 |
|
|
# for receiving data, recv() method will write
|
| 88 |
|
|
# to the signal incoming_packet, and the ipcore must provide a generator
|
| 89 |
|
|
# sensible to that signal. Use the method register_generator()
|
| 90 |
|
|
self.incoming_packet = myhdl.Signal(packet())
|
| 91 |
|
|
self.outgoing_packet = myhdl.Signal(packet())
|
| 92 |
|
|
|
| 93 |
|
|
@myhdl.instance
|
| 94 |
|
|
def outgoing_process():
|
| 95 |
|
|
while True:
|
| 96 |
|
|
yield self.outgoing_packet
|
| 97 |
4 |
dargor |
# multiple tries
|
| 98 |
|
|
for i in range(self.retrytimes):
|
| 99 |
|
|
retval = self.send(self.ipcore_ref, self.localch, self.outgoing_packet.val)
|
| 100 |
|
|
if retval == noc_tbm_errcodes.no_error:
|
| 101 |
|
|
break;
|
| 102 |
|
|
yield myhdl.delay(self.retrydelay)
|
| 103 |
2 |
dargor |
|
| 104 |
|
|
self.generators = [outgoing_process]
|
| 105 |
|
|
self.debugstate()
|
| 106 |
|
|
|
| 107 |
|
|
def register_generator(self, genfunction, **kwargs):
|
| 108 |
|
|
"""
|
| 109 |
|
|
Register a new generator for this ipcore.
|
| 110 |
|
|
|
| 111 |
|
|
Arguments:
|
| 112 |
|
|
* genfunction: function that returns a MyHDL generator
|
| 113 |
|
|
* kwargs: optional keyed arguments to pass to genfunction call
|
| 114 |
|
|
|
| 115 |
|
|
Notes:
|
| 116 |
|
|
* This method requires that genfunction has the following prototype:
|
| 117 |
4 |
dargor |
* my_function(din, dout, tbm_ref, <other_arguments>)
|
| 118 |
2 |
dargor |
* din is a MyHDL Signal of type packet, and is the input signal
|
| 119 |
|
|
to the ipcore. Use this signal to react to input events and
|
| 120 |
|
|
receive input packets.
|
| 121 |
|
|
* dout is a MyHDL Signal of type packet, and is the output
|
| 122 |
|
|
signal to the ipcore. Use this signal to send out packets to
|
| 123 |
|
|
local channel (and then insert into the NoC).
|
| 124 |
4 |
dargor |
* tbm_ref is a reference to an object with logging methods.
|
| 125 |
|
|
(e.g. tbm_ref.info("message") ).
|
| 126 |
2 |
dargor |
* <other_arguments> may be defined, this method use kwargs
|
| 127 |
|
|
argument to pass them.
|
| 128 |
|
|
"""
|
| 129 |
4 |
dargor |
makegen = genfunction(din=self.incoming_packet, dout=self.outgoing_packet, tbm_ref=self, **kwargs)
|
| 130 |
2 |
dargor |
self.debug("register_generator( %s ) generator is %s args %s" % (repr(genfunction), repr(makegen), repr(kwargs)))
|
| 131 |
|
|
self.generators.append(makegen)
|
| 132 |
|
|
|
| 133 |
|
|
# Transaction - related methods
|
| 134 |
|
|
def send(self, src, dest, packet, addattrs=None):
|
| 135 |
|
|
"""
|
| 136 |
|
|
Assumptions:
|
| 137 |
|
|
* Safely ignore src and dest arguments, because this method
|
| 138 |
|
|
is called only by this object generators, therefore it always send
|
| 139 |
|
|
packets to the ipcore related channel.
|
| 140 |
|
|
* In theory src should be self.ipcore_ref, and dest should be
|
| 141 |
|
|
self.localch . This may be checked for errors.
|
| 142 |
|
|
"""
|
| 143 |
|
|
self.debug("-> send( %s , %s , %s , %s )" % (repr(src), repr(dest), repr(packet), repr(addattrs)))
|
| 144 |
|
|
|
| 145 |
|
|
# call recv on the local channel object
|
| 146 |
4 |
dargor |
retval = self.localch.tbm.recv(self.ipcore_ref, self.localch, packet, addattrs)
|
| 147 |
2 |
dargor |
|
| 148 |
|
|
# something to do with the retval? Only report it.
|
| 149 |
|
|
self.debug("-> send returns code '%s'" % repr(retval))
|
| 150 |
|
|
return retval
|
| 151 |
|
|
|
| 152 |
|
|
def recv(self, src, dest, packet, addattrs=None):
|
| 153 |
|
|
"""
|
| 154 |
|
|
Assumptions:
|
| 155 |
|
|
* Safely ignore src and dest arguments, because this method
|
| 156 |
|
|
is called only by local channel object.
|
| 157 |
|
|
* In theory src should be self.localch, and dest should be
|
| 158 |
|
|
self.ipcore_ref . This may be checked for errors.
|
| 159 |
|
|
"""
|
| 160 |
|
|
self.debug("-> recv( %s , %s , %s , %s )" % (repr(src), repr(dest), repr(packet), repr(addattrs)))
|
| 161 |
|
|
|
| 162 |
|
|
# update signal
|
| 163 |
|
|
self.incoming_packet.next = packet
|
| 164 |
|
|
|
| 165 |
4 |
dargor |
self.debug("-> recv returns 'noc_tbm_errcodes.no_error'")
|
| 166 |
|
|
return noc_tbm_errcodes.no_error
|
| 167 |
|
|
|
| 168 |
|
|
# ---------------------------
|
| 169 |
|
|
# Ipcore code generation model
|
| 170 |
|
|
|
| 171 |
|
|
class basic_ipcore_codegen(noc_codegen_ext):
|
| 172 |
|
|
"""
|
| 173 |
|
|
Code generation extension for Ipcore objects.
|
| 174 |
|
|
"""
|
| 175 |
|
|
|
| 176 |
|
|
def __init__(self, codegen_ref):
|
| 177 |
|
|
noc_codegen_ext.__init__(self, codegen_ref)
|
| 178 |
|
|
#self.codegen_ref = codegen_ref
|
| 179 |
|
|
self.ipcore_ref = codegen_ref.nocobject_ref
|
| 180 |
|
|
if not isinstance(self.ipcore_ref, ipcore):
|
| 181 |
|
|
raise TypeError("Argument must be a 'noc_codegen_base' instance defined for a ipcore object.")
|
| 182 |
|
|
|
| 183 |
|
|
# ipcore model: This basic ipcore has some parameters put in the
|
| 184 |
|
|
# generics list, and only one port of type masterwb.
|
| 185 |
|
|
|
| 186 |
|
|
codegen_ref.modulename = "basic_ipcore"
|
| 187 |
|
|
|
| 188 |
|
|
# 1. convert some attributes to generics
|
| 189 |
|
|
codegen_ref.add_generic("name", self.ipcore_ref.name, "Ipcore Name")
|
| 190 |
|
|
codegen_ref.add_generic("address", self.ipcore_ref.router_ref.address, "Ipcore router Address")
|
| 191 |
|
|
|
| 192 |
|
|
# 2. check intercon on ipcore port
|
| 193 |
|
|
|
| 194 |
|
|
ch = self.ipcore_ref.channel_ref
|
| 195 |
|
|
icon = ch.ports[None]["intercon"]
|
| 196 |
|
|
if not isinstance(icon, masterwb_intercon):
|
| 197 |
|
|
raise UserWarning("Port Local on ipcore '%s' does not use intercon 'masterwb_intercon'." % self.ipcore_ref.name)
|
| 198 |
|
|
|
| 199 |
|
|
# 2. convert ipcore port to codegen port
|
| 200 |
|
|
codegen_ref.add_port("PortLocal", None, "Port Local", type=icon.intercon_type)
|
| 201 |
|
|
|
| 202 |
|
|
for signame, sigval in icon.signals.iteritems():
|
| 203 |
|
|
stmp = get_new_signal(
|
| 204 |
|
|
name=signame,
|
| 205 |
|
|
direction=sigval["direction"],
|
| 206 |
|
|
default_value=intbv(0)[sigval["width"]:],
|
| 207 |
|
|
description=sigval["description"])
|
| 208 |
|
|
codegen_ref.add_port("PortLocal", stmp)
|
| 209 |
|
|
|
| 210 |
|
|
# 3. Calculate a Hash with generics and ports info.
|
| 211 |
|
|
# WARNING: You must recalculate the hash when you change the model!
|
| 212 |
|
|
codegen_ref.model_hash()
|
| 213 |
|
|
|
| 214 |
|
|
# 4. Implementation comment
|
| 215 |
|
|
codegen_ref.implementation += "-- Add here implementation code for Ipcore %s" % self.ipcore_ref.name
|
| 216 |
|
|
|
| 217 |
|
|
def add_external_signal(self, name, direction, value, description="", **kwargs):
|
| 218 |
|
|
"""
|
| 219 |
|
|
Wrapper to noc_codegen_base.add_external_signal method, to support hash
|
| 220 |
|
|
updating.
|
| 221 |
|
|
"""
|
| 222 |
|
|
retval = self.codegen_ref.add_external_signal(name, direction, value, description, **kwargs)
|
| 223 |
|
|
self.codegen_ref.model_hash()
|
| 224 |
|
|
return retval
|