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

Subversion Repositories nocmodel

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/nocmodel/trunk/nocmodel/noc_base.py
5,8 → 5,8
# NoC Base Objects
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 03-03-2011
# Version: 0.2
# Date: 05-07-2012
 
#
# This code is free software; you can redistribute it and/or
29,12 → 29,13
# Changelog:
#
# 03-03-2011 : (OD) initial release
# 05-07-2012 : (OD) intercon class, major changes, various bugfixes
#
 
"""
================
=====================
NoCmodel Base Objects
================
=====================
This module declares classes used on a Network-on-chip representation:
42,11 → 43,15
* Router base class
* Channel base class
* IPCore base class
* Intercon base class
* Protocol base class
* Packet class
"""
 
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):
"""
61,6 → 66,16
NoCmodel constructor
"""
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
def add_router(self, name="", with_ipcore=False, **kwargs):
354,27 → 369,36
def router_list(self):
l = []
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
 
def ipcore_list(self):
l = []
for i in self.nodes_iter(data=True):
if i[1]["router_ref"].ipcore_ref != None:
l.append(i[1]["router_ref"].ipcore_ref)
for i in self.router_list():
ip = getattr(i, "ipcore_ref", None)
if ip is not None:
l.append(ip)
return l
 
def channel_list(self):
# this function does not list ipcore channels
def channel_list(self, with_ipcore_channel=False):
l = []
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
def all_list(self):
 
def all_list(self, with_ipcore_channel=False):
l = self.router_list()
l.extend(self.ipcore_list())
l.extend(self.channel_list())
l.extend(self.channel_list(with_ipcore_channel))
return l
 
# query functions
383,6 → 407,14
if r.address == address:
return r
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
def _add_router_from_node(self, node, name="", router_ref=None, **kwargs):
393,7 → 425,7
if router_ref is None:
# index comes from node
if name == "":
name = "R_%d" % node
name = "R_%s" % repr(node)
routernode = router(index=node, name=name, graph_ref=self, **kwargs)
else:
if not isinstance(router_ref, router):
449,6 → 481,15
This base class is used to implement common methods for NoC objects.
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):
"""
Get protocol object for this instance
461,6 → 502,25
# nothing?
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):
"""
IP core base object
490,6 → 550,29
self.graph_ref = None
for key in kwargs.keys():
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):
"""
655,12 → 738,13
router and one ipcore (channel don't have any edge object).
 
Attributes:
* name
* index: optional index on a noc object. Must have an index when it has
* name :
* 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
channel searching). None means it is an ipcore related channel
* graph_ref optional reference to its graph model
* endpoints optional two-item list with references to the connected objects
* graph_ref : optional reference to its graph model
* 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):
# Basic properties
669,9 → 753,56
# Default values
self.graph_ref = None
self.endpoints = [None, None]
self.intercon_class = intercon
self.intercon_class_defargs = {}
for key in kwargs.keys():
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):
"""
Checks if this channel is a special link for an ipcore.
684,8 → 815,295
return True
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
 
This object represents the protocol that the NoC objects use. This
703,9 → 1121,12
 
Attributes:
* 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:
* 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.
At the moment, we recommend using update_packet_field() method to
fill this data structures.
717,20 → 1138,25
Notes:
* 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.packet_format = {}
self.packet_order = []
self.packet_format = OrderedDict()
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():
setattr(self, key, kwargs[key])
def get_protocol_ref(self):
# override to use myself
return self
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 update_packet_field(self, name, type, bitlen, description=""):
"""
Add or update a packet field.
737,24 → 1163,29
Arguments
* 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
* description: optional description of this field
Notes:
* 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"):
raise ValueError("Argument 'type' must be 'int', 'fixed' or 'float'.")
if type not in ("int", "uint", "fixed", "float"):
raise ValueError("Argument 'type' must be 'int', 'uint', 'fixed' or 'float'.")
if name in self.packet_format:
# update field
previdx = self.packet_order.index(name) - 1
previdx = self.packet_format.keys().index(name) - 1
if previdx < 0:
# first field
lastbitpos = 0
else:
lastbitpos = self.packet_format[self.packet_order[previdx]][lsb]
lastbitpos = self.packet_format[self.packet_format.keys()[previdx]]["lsb"]
nextbitpos = lastbitpos + bitlen
self.packet_format[name]["type"] = type
self.packet_format[name]["position"] = previdx + 1
764,23 → 1195,74
self.packet_format[name]["lsb"] = nextbitpos
self.packet_format[name]["msb"] = lastbitpos
# iterate through the rest of the fields adjusting lsb and msb
for idx in range(previdx+2, len(self.packet_order)):
curname = self.packet_order[idx]
for idx in range(previdx+2, len(self.packet_format.keys())):
curname = self.packet_format.keys()[idx]
curbitlen = self.packet_format[curname]["bitlen"]
self.packet_format[curname]["lsb"] = nextbitpos + curbitlen
self.packet_format[curname]["msb"] = nextbitpos
nextbitpos += curbitlen
self.packet_bitlen = nextbitpos
else:
# append
if len(self.packet_format) == 0:
lastbitpos = 0
else:
lastbitpos = self.packet_format[self.packet_order[-1]]["lsb"]
lastbitpos = self.packet_format[self.packet_format.keys()[-1]]["lsb"] + 1
nextbitpos = lastbitpos + bitlen
fieldpos = len(self.packet_order)
self.packet_format[name] = {"type": type, "position": fieldpos, "bitlen": bitlen, "lsb": nextbitpos, "msb": lastbitpos}
self.packet_order.append(name)
fieldpos = len(self.packet_format)
self.packet_format[name] = {"type": type, "position": fieldpos, "bitlen": bitlen, "lsb": nextbitpos - 1, "msb": lastbitpos}
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):
"""
Return a new packet with all required fields.
798,7 → 1280,7
nameless arguments.
"""
retpacket = self.packet_class(protocol_ref=self)
fieldlist = self.packet_order[:]
fieldlist = self.packet_format.keys()
# first named arguments
for fkey, fvalue in kwargs.iteritems():
if fkey in fieldlist:
806,7 → 1288,7
fieldlist.remove(fkey)
# then nameless
for fidx, fvalue in enumerate(args):
fkey = self.packet_order[fidx]
fkey = self.packet_format.keys()[fidx]
if fkey in fieldlist:
retpacket[fkey] = fvalue
fieldlist.remove(fkey)
818,6 → 1300,100
else:
raise ValueError("Missing fields in argument list: %s" % repr(fieldlist))
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):
"""
Register a special packet generator class.
842,13 → 1418,120
 
Attributes:
* 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
def __init__(self, *args, **kwargs):
# look for a protocol_ref key
self.protocol_ref = kwargs.pop("protocol_ref", None)
self.prev_repr = None
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
/nocmodel/trunk/nocmodel/noc_guilib.py
48,6 → 48,7
has_matplotlib = False
 
import networkx as nx
import warnings
 
from noc_base import *
 
64,7 → 65,7
are tuples with x and y positions.
"""
if not has_matplotlib:
print("Function not available")
warnings.warn("Function not available")
return None
 
# node positions
115,4 → 116,5
# box with ipcore labels
ax.text(thepos[0]+ip_relpos[0], thepos[1]+ip_relpos[1], i.name, horizontalalignment="center", bbox=dict(facecolor='green', alpha=0.2))
 
# adjust axis TODO!
plt.show()
/nocmodel/trunk/nocmodel/noc_tbm_base.py
0,0 → 1,308
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# NoC TBM simulation support
# This module declares classes for Transaction Based Model simulation
#
# Author: Oscar Diaz
# Version: 0.2
# Date: 17-03-2011
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 03-03-2011 : (OD) initial release
#
 
"""
===============================
NoCmodel TBM simulation support
===============================
This module declares classes for Transaction Based Model simulation
* Class 'noc_tbm_base'
* Class 'noc_tbm_simulation'
* Class 'noc_tbm_errcodes'
"""
 
import networkx as nx
import myhdl
import logging
 
from noc_base import *
 
import inspect
 
class noc_tbm_base():
"""
Base class for NoC TBM simulator.
This class add methods to a NoC object, required for the TBM model. Each
derived class must override the methods:
* __init__() : its constructor contains the object TBM model (data
structures, generators, etc).
* send()
* recv()
Other methods are related to simulation configuration and logging support.
"""
def __init__(self):
self.log = logging.getLogger()
self.logname = "BASECLASS"
self.generators = []
self.tracesend = []
self.tracerecv = []
 
def __repr__(self):
if self.logname != "":
return "<%s '%s'>" % (self.__class__.__name__, self.logname)
else:
return "<%s at '%d'>" % (self.__class__.__name__, id(self))
 
def get_generators(self):
return self.generators
def _do_build_generators(self):
self.generators.extend(self.build_generators())
# TBM main: every object must define this functions
def send(self, src, dest, data, addattrs=None):
"""
SEND method: this method MUST be called only by the local
object who wants to start a transaction.
This function will call the recv method in the right object.
 
Arguments:
* src: source object (or router address) that call this method, i.e. the
object that starts the transaction.
* dest: destination object (or router address) that receive the data in
the transaction. This method will call dest' recv method.
* data: data to be sent. Can be anything, but normally is an object of
type packet.
* addattrs: optional dictionary with additional arguments
Return: Must return a number: 0 for everything OK, != 0 to show an error
relevant to the caller, an exception in case of attribute error
"""
self.debug("-> send( %s , %s , %s , %s )" % (repr(src), repr(dest), repr(packet), repr(addattrs)))
return noc_tbm_errcodes.not_implemented
 
def recv(self, src, dest, data, addattrs=None):
"""
RECV method: this method MUST be called only by the send
method of the object who started the transaction.
Arguments:
* src: source object (or router address) that call this method, i.e. the
object that starts the transaction.
* dest: destination object (or router address) that receive the data in
the transaction. This method will call dest' recv method.
* data: data to be sent. Can be anything, but normally is an object of
type packet.
* addattrs: optional dictionary with additional arguments
@return Must return a number: 0 for everything OK, != 0 to show an error
relevant to the caller, an exception in case of attribute error
"""
self.debug("-> recv( %s , %s , %s , %s )" % (repr(src), repr(dest), repr(packet), repr(addattrs)))
return noc_tbm_errcodes.not_implemented
# logging methods (only use 4 levels)
def debug(self, msg, *args, **kwargs):
self.log.debug(msg, extra={"objname": self.logname}, *args, **kwargs)
def info(self, msg, *args, **kwargs):
self.log.info(msg, extra={"objname": self.logname}, *args, **kwargs)
def warning(self, msg, *args, **kwargs):
self.log.warning(msg, extra={"objname": self.logname}, *args, **kwargs)
def error(self, msg, *args, **kwargs):
self.log.error(msg, extra={"objname": self.logname}, *args, **kwargs)
 
# special log
def debugstate(self):
self.debug(" '%s' object state: " % repr(self))
for i in dir(self):
# exclude hidden attributes
if i[0] == "_":
continue
self.debug(" ['%s'] = %s " % (i, repr(getattr(self, i))))
def generators_info(self):
self.debug(" Registered generators for '%s': " % repr(self))
for g in self.generators:
self.debug(" '%s': %s" % (getattr(g, "name", "-GEN-"), repr(g)))
 
class noc_tbm_simulation():
"""
NoC TBM simulator object
This class manages the MyHDL simulation on a NoC object and its logging
support.
Attributes:
* noc_ref: reference to NoC model to simulate
* log_file: optional file to save the simulation log
* log_level: optional logging level for the previous file
* kwargs: optional attributes to add to this object
"""
def __init__(self, noc_ref, log_file=None, log_level=logging.INFO, **kwargs):
if isinstance(noc_ref, noc):
self.noc_ref = noc_ref
else:
raise TypeError("This class needs a noc object as constructor argument.")
# configure logging system
# log errors to console, custom log to log_file if specified
addmsg = ""
self.log = logging.getLogger()
self.log.setLevel(log_level)
console_hdl = logging.StreamHandler()
console_hdl.setLevel(logging.WARNING)
class SimTimeFilter(logging.Filter):
def filter(self, record):
record.myhdltime = myhdl.now()
return True
self.log.addFilter(SimTimeFilter())
self.noc_formatter = logging.Formatter("%(myhdltime)4d:%(levelname)-5s:%(objname)-16s - %(message)s")
console_hdl.setFormatter(self.noc_formatter)
self.log.addHandler(console_hdl)
if log_file != None:
file_hdl = logging.FileHandler(log_file, 'w')
file_hdl.setLevel(log_level)
file_hdl.setFormatter(self.noc_formatter)
self.log.addHandler(file_hdl)
addmsg = "and on file (%s) level %s" % (log_file, logging._levelNames[log_level])
# ready to roll
self.debug("Logging enabled! Running log on console level WARNING %s" % addmsg)
 
def configure_simulation(self, max_time=None, add_generators=[]):
"""
Configure MyHDL simulation.
Arguments:
* max_time: optional max time to simulate. None means simulation
without time limit.
* add_generators: external MyHDL generators to add to the simulation
"""
# myhdl simulation: extract all generators and prepare
# arguments
for obj in self.noc_ref.all_list():
prevcount = len(add_generators)
add_generators.extend(obj.tbm.get_generators())
#self.debug("configure_simulation: adding %d generators from object %s" % (len(add_generators)-prevcount, repr(obj)))
if isinstance(obj, ipcore):
add_generators.extend(obj.channel_ref.tbm.get_generators())
#self.debug("configure_simulation: plus ipcore channel: adding %d generators from object %s" % (len(add_generators)-prevcount, repr(obj.channel_ref)))
# --------------------------------
# debug info
# TODO: try to get info about generators, particularly obtain origin
# info about @always and @always_comb generators
#self.debug("configure_simulation: list of generators: (count = %d)" % len(add_generators))
#for genl in add_generators:
#if not isinstance(genl, list):
#gen2 = [genl]
#else:
#gen2 = genl
#self.debug("configure_simulation: generator list '%s'" % repr(genl))
#for gen in gen2:
#self.debug("configure_simulation: generator '%s'" % repr(gen))
#try:
#self.debug("configure_simulation: inspect info name '%s'" % gen.gen.__name__)
#self.debug("configure_simulation: inspect info locals '%s'" % repr(gen.gen.gi_frame.f_locals.keys()))
#for k, v in gen.gen.gi_frame.f_locals.iteritems():
#self.debug("configure_simulation: inspect info locals[%s] '%s'" % (k, repr(v)))
#if gen.gen.__name__ == "genfunc":
#self.debug("configure_simulation: inspect info deep name '%s'" % gen.func.__name__)
#except:
#pass
# --------------------------------
self.sim_object = myhdl.Simulation(*add_generators)
self.sim_duration = max_time
self.debug("configure_simulation: will run until simulation time '%d'" % max_time)
 
def run(self):
"""
Run MyHDL simulation
"""
self.debug("Start simulation")
self.sim_object.run(self.sim_duration)
self.debug("End simulation")
 
# custom logging methods (only use 4 levels)
def debug(self, msg, *args, **kwargs):
self.log.debug(msg, extra={"objname": "TopNoC"}, *args, **kwargs)
def info(self, msg, *args, **kwargs):
self.log.info(msg, extra={"objname": "TopNoC"}, *args, **kwargs)
def warning(self, msg, *args, **kwargs):
self.log.warning(msg, extra={"objname": "TopNoC"}, *args, **kwargs)
def error(self, msg, *args, **kwargs):
self.log.error(msg, extra={"objname": "TopNoC"}, *args, **kwargs)
 
# special log filter: log individually by object name
def configure_byobject_logging(self, basefilename="", log_level=logging.INFO):
"""
Special log filter: log individually by object name
Arguments:
* basefilename: generated filenames will start with this string
* log_level: optional logging level for previous files
"""
# base filter
class ObjFilter(logging.Filter):
def __init__(self, basename):
self.basename = basename
def filter(self, record):
if record.objname == self.basename:
return True
return False
# need a handler for each object
for obj in self.noc_ref.all_list():
newfilter = ObjFilter(obj.tbm.logname)
newhandler = logging.FileHandler("%s_%s.log" % (basefilename, obj.tbm.logname), "w")
newhandler.setLevel(log_level)
newhandler.addFilter(newfilter)
newhandler.setFormatter(self.noc_formatter)
self.log.addHandler(newhandler)
# Transactions logger
class TransFilter(logging.Filter):
def filter(self, record):
if record.message.find("->") == 0:
return True
return False
newhandler = logging.FileHandler("%s_transactions.log" % basefilename, "w")
newhandler.setLevel(log_level)
newhandler.addFilter(TransFilter())
newhandler.setFormatter(self.noc_formatter)
self.log.addHandler(newhandler)
# TopNoC will not be added to this set
self.debug("Special logging enabled. basefilename=%s level %s" % (basefilename, logging._levelNames[log_level]))
 
class noc_tbm_errcodes():
"""
Common error codes definition
"""
no_error = 0
full_fifo = -1
packet_bad_data = -2
tbm_badcall_recv = -3
tbm_badcall_send = -4
tbm_busy_channel = -5
not_implemented = -15
/nocmodel/trunk/nocmodel/noc_codegen_base.py
0,0 → 1,520
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# NoC Code generator
# This module defines the basic structure for code generation
#
# Author: Oscar Diaz
# Version: 0.2
# Date: 11-11-2011
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 11-11-2011 : (OD) initial release
#
 
"""
Base for code generation support
 
This module defines:
* Class 'noc_codegen_base'
* Class 'noc_codegen_ext'
"""
 
from myhdl import intbv, SignalType
from nocmodel import *
 
#import scipy
#import networkx as nx
from copy import deepcopy
from sys import exc_info
import warnings
 
class noc_codegen_base():
"""
Base class for code generator
This class holds a basic model of a hardware description. Although inspired
in VHDL, it also holds for Verilog.
Note that its necessary a defined noc model to generate this code model.
Note that this class is meant to be extended by a particular code generator:
VHDL generator, Verilog generator, etc.
This object will assume a module has the following sections:
--------------------
<docheader> : File header and documentation about the module
<libraries> : Declarations at the beginning (VHDL: libraries declarations)
<modulename> : Module name (VHDL: entity name)
<generics> : Parameters for the module (VHDL: generics inside an entity)
<ports> : Declaration of inputs and outputs (VHDL: ports inside an entity)
<implementation> : Code implementation (pure VHDL or Verilog code)
--------------------
Objects type:
* docheader, libraries, modulename and implementation are simple strings.
* generics are list of dictionaries with this required keys:
* "class" : always "generic"
* "name"
* "type" : string formatted data type
* "type_array" : 2-element list of strings that declares array boundaries
either using numbers or generics names. None for simple data types
* "default_value"
* "current_value"
* "description"
* ports are list of dictionaries with this required keys:
* "class" : always "port"
* "name"
* "type" : port type, if applicable
* "nocport" : index to related port in the nocobject' ports dictionary or
others signal containers in the nocobject.
* "signal_list" : list of signals that compose the port
* "description"
* external_signals are list of signals that aren't related to any port.
* signals are dictionaries with this required keys:
* "class" : always "signal"
* "name"
* "type" : string formatted data type
* "type_array" : 2-element list of strings that declares array boundaries
either using numbers or generics names. None for simple data types
* "direction"
* "default_value"
* "related_generics" : when the data type is an array, this list has
references to generics to be used to build array declaration.
* "description"
Attributes:
* modulename
* nocobject_ref
* docheader
* libraries
* generics
* ports
* external_signals
* implementation
* interface_hash
Notes:
* Code generation methods are meant to return strings. The user is
responsible to write it in files.
* This object maintains the code model and use it to generate code. Any
particular changes or adjustments to the model should be done by a
'noc_codegen_ext' object.
* This code generation model are restricted to noc models, because
routers and ipcores are generated by MyHDL code converter (this
could change if the noc objects needs to keep hierarchy in its
internal implementation).
This converter keeps routers and ipcores hierarchy.
"""
def __init__(self, nocobject_ref, **kwargs):
# nocobject reference
if not isinstance(nocobject_ref, (nocobject, noc)):
raise TypeError("Argument must be an instance of nocobject or noc class")
self.nocobject_ref = nocobject_ref
# External conversion flag
self.external_conversion = False
 
# string type objects
self.docheader = ""
self.libraries = ""
self.modulename = ""
# list of dictionaries (generic and port)
self.generics = []
self.ports = []
self.external_signals = []
# implementation
self.implementation = ""
# module hash
self.interface_hash = ""
# optional arguments
for key in kwargs.keys():
setattr(self, key, kwargs[key])
# main methods
def generate_file(self):
"""
Generate the entire file that implements this object.
"""
raise NotImplementedError("What language for code generation?")
def generate_component(self):
"""
Generate a component definition for this object.
"""
raise NotImplementedError("What language for code generation?")
 
def generate_generic_declaration(self, generic=None, with_default=False):
"""
Generate a generic declaration for this object.
Arguments:
* generic : either a name or a list index for a particular generic
* with_default : True to add the default value
Returns:
* A string when generic argument is used
* A list of strings with all generics
"""
raise NotImplementedError("What language for code generation?")
 
def generate_port_declaration(self, port=None, with_default=False):
"""
Generate a port declaration for this object.
Arguments:
* port : either a name or a list index for a particular port
* with_default : True to add the default value
Returns:
* A list of strings with all signals in port when port argument is used
* A list of strings with all signals in all ports
"""
raise NotImplementedError("What language for code generation?")
def generate_signal_declaration(self, inport=None, signal=None, with_default=False):
"""
Generate a signal declaration for this object.
Arguments:
* inport : either a name or a list index for a particular port. None
means use the external_signals list
* signal : either a name or a list index for a particular signal
* with_default : True to add the default value
Returns:
* A string when signal argument is used
* A list of strings with all signals
"""
raise NotImplementedError("What language for code generation?")
def make_comment(self, data):
"""
Convert string data to language comment
Argument:
* data: string or list of strings to convert
Returns: string or list of strings with comments added.
"""
raise NotImplementedError("What language for code generation?")
def add_tab(self, data, level=1):
"""
Add an indentation level to the string
Argument:
* data: string or list of strings
* level: how many indentation levels to add. Default 1
Returns: string or list of strings with <level> indentation levels.
"""
raise NotImplementedError("What language for code generation?")
def to_valid_str(self, str_in):
"""
Convert an input string, changing special characters used on
the HDL language. Useful for set names .
Argument:
* str_in: string to convert
Returns: the converted string.
"""
raise NotImplementedError("What language for code generation?")
 
# codegen model management
def add_generic(self, name, value, description="", **kwargs):
"""
Add a generic to the model.
 
Arguments:
* name : must be a string
* value : default value for this generic
* description :
* Optional arguments (just for method call format)
Returns:
* Reference to added generic dictionary.
Note:
* This method can override an existing generic entry.
* This basic method just add name, default value and description.
Extended class methods must fill correct type arguments.
"""
if not isinstance(name, str):
raise TypeError("Name must be string, not '%s'." % repr(name))
 
# supported types:
if not isinstance(value, (bool, int, intbv, str)):
raise TypeError("Unsupported type '%s'." % repr(type(value)))
 
# check if new entry
g = filter(lambda x: x["name"] == name, self.generics)
if len(g) == 0:
g = get_new_generic(name = name)
self.generics.append(g)
else:
g = g[0]
g.update(default_value = value, description = description)
# optional kwargs
g.update(kwargs)
# return reference to added generic dict
return g
def add_port(self, name, signal_desc=None, description="", **kwargs):
"""
Add a port to the model.
 
Arguments:
* name : must be a string
* signal_desc : optional dictionary with signal information included.
None to just add/update port without changing its signals.
* description :
* Optional arguments (just for method call format)
Returns:
* Reference to added port dictionary.
Note:
* This method can add a new port or update an existing port with new
signals.
* This basic method just add name and description, and update a signal
using signal_desc information. Extended class methods must fill
correct type arguments in the updated signal.
"""
if not isinstance(name, str):
raise TypeError("Name must be string, not '%s'." % repr(name))
 
# check signal dict keys: must have at least class and name
if signal_desc is not None:
if not all([x in signal_desc for x in ("class", "name")]):
raise TypeError("Argument signal_desc must be a signal dict ('%s')." % repr(signal_desc))
if signal_desc["class"] != "signal":
raise TypeError("Argument signal_desc must be a signal dict ('%s')." % repr(signal_desc))
 
# check if new entry
p = filter(lambda x: x["name"] == name, self.ports)
if len(p) == 0:
p = get_new_port(name = name)
self.ports.append(p)
else:
p = p[0]
 
# only update description when string is non-empty
if description != "":
p.update(description = description)
 
# check existing signal
if signal_desc is not None:
sig = filter(lambda x: x["name"] == signal_desc["name"], p["signal_list"])
if len(sig) == 0:
p["signal_list"].append(signal_desc)
else:
sig[0].update(signal_desc)
# optional kwargs
p.update(kwargs)
# return reference to added/updated port dict
return p
def add_external_signal(self, name, direction, value, description="", **kwargs):
"""
Add a external signal to the model.
 
Arguments:
* name : must be a string
* direction : "in" or "out"
* value : initial value for this port
* description
* Optional arguments (just for method call format)
Returns:
* Reference to added external_signals dictionary.
Note:
* This method can override an existing signal entry.
* This basic method just add name, direction, intial value and
description. Extended class methods must fill correct type arguments.
"""
if not isinstance(name, str):
raise TypeError("Name must be string, not '%s'." % repr(name))
 
# supported types:
if isinstance(value, SignalType):
value = value._init
if not isinstance(value, (bool, int, intbv)):
raise TypeError("Unsupported type '%s'." % repr(type(value)))
if direction not in ["in", "out"]:
raise ValueError("Direction must be 'in' or 'out', not '%s'." % repr(direction))
# check if new entry
sig = filter(lambda x: x["name"] == name, self.external_signals)
if len(sig) == 0:
sig = get_new_signal(name = name)
self.external_signals.append(sig)
else:
sig = sig[0]
sig.update(direction = direction, default_value = value, description = description)
# optional kwargs
sig.update(kwargs)
# return reference to added generic dict
return sig
def build_implementation(self):
"""
Try to generate the implementation section. Check if a "codemodel"
object exists and try to call "generate_implementation" method.
If the call is successful, self.implementation will store its return
string. Do nothing on failure (report a warning).
"""
if hasattr(self.nocobject_ref, "codemodel"):
implementation = ""
if not hasattr(self.nocobject_ref.codemodel, "generate_implementation"):
warnings.warn("Method 'generate_implementation()' not found.")
elif not callable(self.nocobject_ref.codemodel.generate_implementation):
warnings.warn("Attribute 'generate_implementation()' not callable")
else:
implementation = self.nocobject_ref.codemodel.generate_implementation()
##except:
### Report a warning instead of the exception
##exctype, value = exc_info()[:2]
##warnings.warn("%s: %s" % (exctype, value))
if isinstance(implementation, str):
self.implementation = implementation
 
def model_hash(self):
"""
Calculate a hash string based on the nocobject interface: Generics,
ports and external signals.
Two nocobject with the same model hash can be instantiated by the same
module code (with different generics' values).
Returns: a string with a predefined format.
"""
hash_str = ""
# 1. Generics information
hash_gen = []
for g in self.generics:
hash_gen.append([g["name"], g["type"]])
# sort generics by name
hash_gen.sort(key = lambda x: x[0])
# add a stream of "<name><type>"
for g in hash_gen:
hash_str += "%s%s" % (g[0], g[1])
# 2. Ports information
hash_port = []
for g in self.ports:
hash_port.append([g["name"], g["type"], len(g["signal_list"])])
# sort ports by name
hash_port.sort(key = lambda x: x[0])
# add a stream of "<name><type><num-of-signals>"
for g in hash_port:
hash_str += "%s%s" % (g[0], g[1])
# 3. External ports information
hash_ext = []
for g in self.external_signals:
hash_ext.append([g["name"], g["type"], g["direction"]])
# sort external_signals by name
hash_ext.sort(key = lambda x: x[0])
# add a stream of "<name><type><direction>"
for g in hash_ext:
hash_str += "%s%s" % (g[0], g[1])
self.interface_hash = hash_str
return hash_str
class noc_codegen_ext():
"""
Extension class for code generator
This class supports an access point to do transformations on a
'noc_codegen_base' code model.
This transformation methods should be declared on extended classes of this
class, and are close related to the particular noc object.
Notes:
* This object maintains the code model and use it to generate code. Any
particular changes or adjustments to the model should be done by a
'noc_codegen_ext' object. Usually this object is related to a particular
nocobject (router, ipcore or channel).
"""
def __init__(self, codegen_ref):
# must be related to a noc_codegen_base object
if not isinstance(codegen_ref, noc_codegen_base):
raise TypeError("Argument must be an instance of 'noc_codegen_base' class")
self.codegen_ref = codegen_ref
self.nocobject_ref = codegen_ref.nocobject_ref
 
# helper structures:
# base objects for generics, ports and signals
_empty_generic = {
"class": "generic",
"name": "",
"type": "",
"type_array": [None, None],
"default_value": "",
"current_value": "",
"description": ""}
_empty_port = {
"class": "port",
"name": "",
"type": "",
"nocport": None,
"signal_list": [],
"description": ""}
_empty_signal = {
"class": "signal",
"name": "",
"type": "",
"type_array": [None, None],
"direction": "",
"default_value": "",
"related_generics": [],
"description": ""}
 
# new structures generation
def get_new_generic(**kwargs):
s = deepcopy(_empty_generic)
s.update(kwargs)
return s
def get_new_port(**kwargs):
s = deepcopy(_empty_port)
s.update(kwargs)
return s
def get_new_signal(**kwargs):
s = deepcopy(_empty_signal)
s.update(kwargs)
return s
/nocmodel/trunk/nocmodel/noc_rtl_myhdl.py
0,0 → 1,259
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# NoC RTL support in MyHDL
# This module adds support for mixed model and RTL descriptions in MyHDL
#
# Author: Oscar Diaz
# Version: 0.2
# Date: 01-06-2012
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 03-03-2011 : (OD) initial release
# 01-06-2012 : (OD) big refactorization
#
 
"""
===============================
NoCmodel RTL MyHDL support
===============================
This module extends 'noc_tbm_base' class for RTL descriptions in MyHDL
* Class 'noc_rtl_myhdl_base'
"""
 
import myhdl
 
from nocmodel import *
from noc_tbm_base import *
 
class noc_rtl_myhdl_base(noc_tbm_base):
"""
Extended class for a MyHDL description of a NoC router.
This class adds support for behavioral - RTL mixed modeling and
full RTL modeling. It is meant to add in NoC objects through
multiple inheritance mechanism
Features:
* Keep a list of (Intercon type) interface objects, each object is
indexed by a port index and each object stores a list of signals
dict: "interface_objects"
* Keep a list of external interface objects. Each object is a set of
signals (use "signalset" class), and are accessed by any python
object (a string is recommended).
dict: "external_objects"
* Keep a list of internal MyHDL signals, and provides correct references
dict: "internal_signals"
"""
# Interface objects methods
def add_interface(self, port_idx, object_ref=None):
"""
Add a new interface
Arguments:
"""
if not hasattr(self, "interface_objects"):
self._new_interface_objects()
self.interface_objects[port_idx] = object_ref
return object_ref
 
def get_interface_signal(self, port_idx, signalname):
"""
Try to get a signal reference from the interface object indexed by
"port_idx". Raise an Exception if not found.
Arguments:
* port_idx:
* signalname:
Returns:
the MyHDL signal reference
"""
if not hasattr(self, "interface_objects"):
self._new_interface_objects()
if port_idx not in self.interface_objects:
raise ValueError("%s : Interface '%s' not found." % (repr(self), repr(port_idx)))
# check if object is list-dict type or a class with signal attributes
if isinstance(self.interface_objects[port_idx], (tuple, list, dict)):
# indexing lookup
if signalname not in self.interface_objects[port_idx]:
raise AttributeError("%s : Signal '%s' from Interface %s not found." % (repr(self), signalname, repr(port_idx)))
return self.interface_objects[port_idx][signalname]
else:
# attribute lookup
try:
return getattr(self.interface_objects[port_idx], signalname)
except:
raise AttributeError("%s : Signal '%s' from Interface %s not found." % (repr(self), signalname, repr(port_idx)))
def get_interface_all_signals(self, port_idx):
"""
Return a dict with all signals references from interface
Arguments:
* port_idx:
Returns:
dict with references to all signals in interface
"""
if not hasattr(self, "interface_objects"):
self._new_interface_objects()
return {}
if port_idx not in self.interface_objects:
raise ValueError("%s : Interface '%s' not found." % (repr(self), repr(port_idx)))
if isinstance(self.interface_objects[port_idx], dict):
return self.interface_objects[port_idx]
elif isinstance(self.interface_objects[port_idx], (tuple, list)):
return dict([(k, v) for k, v in enumerate(self.interface_objects[port_idx])])
else:
# search through all attributes
retval = {}
for attrname in dir(self.interface_objects[port_idx]):
attr = getattr(self.interface_objects[port_idx], attrname)
if isinstance(attr, myhdl.SignalType):
retval[attrname] = attr
return retval
# External interface objects methods
def add_external_interface(self, index, object_ref=None):
if not hasattr(self, "external_objects"):
self._new_external_objects()
if index is None:
raise ValueError("Index cannot be None.")
# Use an intercon object to model the external
# interface objects.
if object_ref is not None:
if not isinstance(object_ref, signalset):
raise ValueError("Object_ref must be of signalset type (not %s, type %s)" % (repr(object_ref), type(object_ref)))
else:
object_ref = signalset(index)
self.external_objects[index] = object_ref
return object_ref
def get_external_signal(self, index, signalname):
"""
Try to get a signal reference from the external interface object
indexed by "index". Raise an Exception if not found.
Arguments:
* index:
* signalname:
Returns:
the MyHDL signal reference
"""
if not hasattr(self, "external_objects"):
self._new_external_objects()
if index is None:
# special case: search through all external interfaces
siglist = []
for sigset in self.external_objects.itervalues():
try:
siglist.append(sigset.get_signal_ref(signalname))
except:
pass
if len(siglist) == 0:
raise ValueError("%s : signal '%s' not found in any of the external objects." % (repr(self), repr(signalname)))
elif len(siglist) > 1:
raise ValueError("%s : signal '%s' found on multiple external objects." % (repr(self), repr(signalname)))
else:
return siglist[0]
if index not in self.external_objects:
raise ValueError("%s : External interface '%s' not found." % (repr(self), repr(index)))
return self.external_objects[index].get_signal_ref(signalname)
def get_external_all_signals(self, index):
"""
Return a dict with all signals references from interface
Arguments:
* index:
Returns:
dict with references to all signals in interface
"""
if not hasattr(self, "external_objects"):
self._new_external_objects()
if index not in self.external_objects:
raise ValueError("%s : External interface '%s' not found." % (repr(self), repr(index)))
retval = {}
for signalname in self.external_objects[index].get_signal_allnames():
retval[signalname] = self.external_objects[index].get_signal_ref(signalname)
return retval
 
# Internal signals methods
def getset_internal_signal(self, signalname, newsignal_ref=None):
"""
Try to get a reference to a internal signal with name "signalname".
If not found, optionally add a new signal with its reference
in "newsignal_ref".
Arguments:
* signalname:
* newsignal_ref:
Returns:
the MyHDL signal reference, or the contents of "newsignal_ref"
"""
if not hasattr(self, "internal_signals"):
self._new_internal_signals()
if signalname not in self.internal_signals:
if newsignal_ref is not None:
if isinstance(newsignal_ref, myhdl.SignalType):
self.internal_signals[signalname] = newsignal_ref
else:
# build a new signal based on newsignal_ref
self.internal_signals[signalname] = myhdl.Signal(newsignal_ref)
else:
raise ValueError("%s : Signal '%s' not found." % (repr(self), signalname))
return self.internal_signals[signalname]
def internal_signal_iter(self):
"""
Return an iterator object over all the internal signals.
This iterator works with tuples (signame, sigref).
"""
return self.internal_signals.iteritems()
# Methods to override
def build_generators_codegen(self, withbaseclass=True):
"""
Separate generator builder, for hw generators only
NOTES:
* Generators in this method must be convertible
* Use overridden functions
"""
raise NotImplementedError
def _new_internal_signals(self):
self.internal_signals = {}
def _new_external_objects(self):
self.external_objects = {}
def _new_interface_objects(self):
self.interface_objects = {}
/nocmodel/trunk/nocmodel/basicmodels/basic_channel.py
3,7 → 3,7
 
#
# Basic Channel model
# * TLM model
# * TBM model
#
# Author: Oscar Diaz
# Version: 0.1
33,17 → 33,17
#
 
"""
Basic channel TLM model
Basic channel TBM model
"""
 
from nocmodel.noc_tlm_base import *
from nocmodel.noc_tbm_base import *
 
# ---------------------------
# Channel TLM model
# Channel TBM model
 
class basic_channel_tlm(noc_tlm_base):
class basic_channel_tbm(noc_tbm_base):
"""
TLM model of a NoC channel. It models a simple FIFO channel with
TBM model of a NoC channel. It models a simple FIFO channel with
adjustable delay. This channel will move any kind of data as a whole, but
ideally will move packet objects.
53,8 → 53,8
Notes:
*This model is completely behavioral
"""
def __init__(self, channel_ref, channel_delay=1):
noc_tlm_base.__init__(self)
def __init__(self, channel_ref, channel_delay=2):
noc_tbm_base.__init__(self)
if isinstance(channel_ref, channel):
self.channel_ref = channel_ref
self.graph_ref = channel_ref.graph_ref
77,7 → 77,7
if self.channel_delay > 0:
self.has_delay = True
self.delay_fifo = []
self.delay_fifo_max = 10 # error-catch parameter, avoid fifo excessive growing
self.delay_fifo_max = 4 # error-catch parameter, avoid fifo excessive growing
self.delay_event = myhdl.Signal(False)
# implement delay generator
@myhdl.instance
88,18 → 88,20
timed_packet = self.delay_fifo.pop(0)
# calculate the exact delay value
next_delay = self.channel_delay - (myhdl.now() - timed_packet[0])
if next_delay <= 0:
# time could be 0, when the packets arrive from both endpoints
# at the same time. In that case don't yield
if next_delay < 0:
self.debug("delay_generator CATCH next_delay is '%d'" % next_delay)
else:
elif next_delay > 0:
yield myhdl.delay(next_delay)
self.debug("delay_generator sending delayed packet (by %d), timed_packet format %s" % (next_delay, repr(timed_packet)) )
# use send()
retval = self.send(*timed_packet[1:])
# what to do in error case? report and continue
if retval != noc_tlm_errcodes.no_error:
if retval != noc_tbm_errcodes.no_error:
self.error("delay_generator send returns code '%d'?" % retval )
self.delay_event.next = False
yield self.delay_event
yield self.delay_event.posedge
self.generators.append(delay_generator)
 
self.debugstate()
118,20 → 120,26
thedest = self.graph_ref.get_router_by_address(dest)
if thedest == False:
self.error("-> send: dest %s not found" % repr(dest) )
return noc_tlm_errcodes.tlm_badcall_send
return noc_tbm_errcodes.tbm_badcall_send
elif isinstance(dest, (router, ipcore)):
thedest = dest
else:
self.error("-> send: what is dest '%s'?" % repr(dest) )
return noc_tlm_errcodes.tlm_badcall_send
return noc_tbm_errcodes.tbm_badcall_send
 
# check dest as one of the channel endpoints
if thedest not in self.endpoints:
self.error("-> send: object %s is NOT one of the channel endpoints [%s,%s]" % (repr(thedest), repr(self.endpoints[0]), repr(self.endpoints[1])) )
return noc_tlm_errcodes.tlm_badcall_send
return noc_tbm_errcodes.tbm_badcall_send
# call trace functions
traceargs = {"self": self, "src": src, "dest": dest, "packet": packet, "addattrs": addattrs}
for f in self.tracesend:
if callable(f):
f(traceargs)
 
# call recv on the dest object
retval = thedest.tlm.recv(self.channel_ref, dest, packet, addattrs)
retval = thedest.tbm.recv(self.channel_ref, dest, packet, addattrs)
 
# Something to do with the retval? Only report it.
self.debug("-> send returns code '%s'" % repr(retval))
150,17 → 158,23
thesrc = self.graph_ref.get_router_by_address(src)
if thesrc == False:
self.error("-> recv: src %s not found" % repr(src) )
return noc_tlm_errcodes.tlm_badcall_recv
return noc_tbm_errcodes.tbm_badcall_recv
elif isinstance(src, (router, ipcore)):
thesrc = src
else:
self.error("-> recv: what is src '%s'?" % repr(src) )
return noc_tlm_errcodes.tlm_badcall_recv
return noc_tbm_errcodes.tbm_badcall_recv
 
# check src as one of the channel endpoints
if thesrc not in self.endpoints:
self.error("-> recv: object %s is NOT one of the channel endpoints [%s,%s]" % (repr(thesrc), repr(self.endpoints[0]), repr(self.endpoints[1])) )
return noc_tlm_errcodes.tlm_badcall_recv
return noc_tbm_errcodes.tbm_badcall_recv
# call trace functions
for f in self.tracerecv:
if callable(f):
traceargs = {"self": self, "src": src, "dest": dest, "packet": packet, "addattrs": addattrs}
f(traceargs)
 
# calculate the other endpoint
end_index = self.endpoints.index(thesrc) - 1
174,7 → 188,7
self.warning("-> recv: delay_fifo is getting bigger! current size is %d" % len(self.delay_fifo) )
# trigger event
self.delay_event.next = True
retval = noc_tlm_errcodes.no_error
retval = noc_tbm_errcodes.no_error
else:
# use send() call directly
router_dest = self.endpoints[end_index]
/nocmodel/trunk/nocmodel/basicmodels/__init__.py
42,6 → 42,8
* Module basic_ipcore
* Module basic_protocol
* Module basic_router
* Module intercon_model
* Module basic_noc_codegen
"""
 
# provided modules
49,5 → 51,7
from basic_ipcore import *
from basic_protocol import *
from basic_router import *
from intercon_model import *
from basic_noc_codegen import *
 
__version__ = "0.1"
/nocmodel/trunk/nocmodel/basicmodels/basic_router.py
3,11 → 3,12
 
#
# Basic Router model
# * TLM model
# * TBM model
# * Code generation model
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 03-03-2011
# Version: 0.2
# Date: 14-03-2011
 
#
# This code is free software; you can redistribute it and/or
30,20 → 31,24
# Changelog:
#
# 03-03-2011 : (OD) initial release
# 14-03-2011 : (OD) adding code generation model
#
 
"""
Basic router TLM model
* Basic router TBM model
* Router code generation model
"""
 
from nocmodel.noc_tlm_base import *
from nocmodel.noc_tbm_base import *
from nocmodel.noc_codegen_base import *
from intercon_model import *
 
# ---------------------------
# Router TLM model
# Router TBM model
 
class basic_router_tlm(noc_tlm_base):
class basic_router_tbm(noc_tbm_base):
"""
TLM model of a NoC router. This router uses store-and-forward technique,
TBM model of a NoC router. This router uses store-and-forward technique,
using the routing information from the router object. This model just
forward the packet, and if the packet is in its router destination, send it
to its ipcore. Each package that the ipcore generates is delivered
57,8 → 62,8
* This model is completely behavioral.
* See code comments to better understanding.
"""
def __init__(self, router_ref, fifo_len=4):
noc_tlm_base.__init__(self)
def __init__(self, router_ref, fifo_len=5):
noc_tbm_base.__init__(self)
if isinstance(router_ref, router):
self.router_ref = router_ref
self.graph_ref = router_ref.graph_ref
91,6 → 96,7
p["fifo_out"] = []
p["fifo_in_event"] = myhdl.Signal(False)
p["fifo_out_event"] = myhdl.Signal(False)
self.idlesignal = myhdl.Signal(True)
 
# extract a list of all fifo event signals
self.list_fifo_in_events = [i["fifo_in_event"] for i in self.ports_info.itervalues()]
123,6 → 129,7
while True:
for port, data in self.ports_info.iteritems():
if len(data["fifo_out"]) > 0:
self.idlesignal.next = False
if not data["fifo_out_event"].val:
self.debug("flush_fifo_out CATCH fifo not empty and NO trigger! fifo has %s" % repr(data["fifo_out"]))
self.info("flush_fifo_out event in port %d" % port)
130,11 → 137,13
self.debug("flush_fifo_out port %d packet is %s (delay %d)" % (port, repr(packet), self.delay_outfromfifo))
# DELAY model: time to move from fifo to external port in destination object
yield myhdl.delay(self.delay_outfromfifo)
self.idlesignal.next = False
# try to send it
retval = self.send(self.router_ref, data["channel"], packet)
if retval == noc_tlm_errcodes.no_error:
if retval == noc_tbm_errcodes.no_error:
# clean trigger
data["fifo_out_event"].next = False
self.debug("flush_fifo_out clean trigger. list %s" % repr(self.list_fifo_out_events))
#continue
else:
self.error("flush_fifo_out FAILED in port %d (code %d)" % (port, retval))
142,6 → 151,11
#TODO: temporally put back to fifo
self.info("flush_fifo_out packet went back to fifo.")
data["fifo_out"].append(packet)
else:
if data["fifo_out_event"].val:
self.debug("flush_fifo_out CATCH fifo_out empty and trigger ON! Cleaning trigger")
data["fifo_out_event"].next = False
self.idlesignal.next = True
yield self.list_fifo_out_events
self.debug("flush_fifo_out event hit. list %s" % repr(self.list_fifo_out_events))
 
152,6 → 166,7
# routing update: check all fifos
for port, data in self.ports_info.iteritems():
while len(data["fifo_in"]) > 0:
self.idlesignal.next = False
if not data["fifo_in_event"].val:
self.debug("routing_loop CATCH fifo not empty and NO trigger! fifo has %s" % repr(data["fifo_in"]))
self.info("routing_loop fifo_in event in port %d" % port)
166,15 → 181,24
self.debug("routing_loop port %d to port %s (dest %d)" % (port, nextaddr, destaddr))
# DELAY model: time spent to make a route decisition
yield myhdl.delay(self.delay_route)
self.idlesignal.next = False
self.ports_info[nextaddr]["fifo_out"].append(packet)
# fifo trigger
if self.ports_info[nextaddr]["fifo_out_event"]:
self.debug("routing_loop CATCH possible miss event because port %d fifo_out_event=True", self.myaddress)
self.ports_info[nextaddr]["fifo_out_event"].next = True
# assuming empty fifo_in
if data["fifo_in_event"].val:
self.debug("routing_loop CATCH fifo_in empty and trigger ON! Cleaning trigger")
data["fifo_in_event"].next = False
self.idlesignal.next = True
self.debug("routing_loop idle. fifo_in_events list %s" % repr(self.list_fifo_in_events))
if not any(self.list_fifo_in_events):
yield self.list_fifo_in_events
else:
self.debug("routing_loop pending fifo_in_events list %s" % repr(self.list_fifo_in_events))
self.debug("routing_loop fifo_in event hit. list %s" % repr(self.list_fifo_in_events))
 
yield self.list_fifo_in_events
self.debug("routing_loop event hit. list %s" % repr(self.list_fifo_in_events))
 
# list of all generators
self.generators.extend([flush_fifo_out, routing_loop])
self.debugstate()
195,7 → 219,7
therouter = self.graph_ref.get_router_by_address(dest)
if therouter == False:
self.error("-> send: dest %s not found" % repr(dest) )
return noc_tlm_errcodes.tlm_badcall_send
return noc_tbm_errcodes.tbm_badcall_send
# extract channel ref from ports_info
thedest = self.ports_info[therouter.address]["channel"]
elif isinstance(dest, router):
206,10 → 230,10
thedest = dest
else:
self.error("-> send: what is dest '%s'?" % repr(dest) )
return noc_tlm_errcodes.tlm_badcall_send
return noc_tbm_errcodes.tbm_badcall_send
 
# call recv on the dest channel object
retval = thedest.tlm.recv(self.router_ref, thedest, packet, addattrs)
retval = thedest.tbm.recv(self.router_ref, thedest, packet, addattrs)
 
# TODO: something to do with the retval?
self.debug("-> send returns code '%s'" % repr(retval))
242,10 → 266,10
thesrc = theend.router_ref.address
else:
self.error("-> recv: what is endpoint '%s' in channel '%s'?" % (repr(theend), repr(src)) )
return noc_tlm_errcodes.tlm_badcall_recv
return noc_tbm_errcodes.tbm_badcall_recv
else:
self.error("-> recv: what is src '%s'?" % repr(src) )
return noc_tlm_errcodes.tlm_badcall_recv
return noc_tbm_errcodes.tbm_badcall_recv
 
# thesrc becomes the port number
# check if there is enough space on the FIFO
252,13 → 276,108
if len(self.ports_info[thesrc]["fifo_in"]) == self.fifo_len:
# full FIFO
self.error("-> recv: full fifo. Try later.")
return noc_tlm_errcodes.full_fifo
self.debug("-> recv: port %s fifo_in contents: %s" % (thesrc, repr(self.ports_info[thesrc]["fifo_in"])))
return noc_tbm_errcodes.full_fifo
# get into fifo
self.ports_info[thesrc]["fifo_in"].append(packet)
# trigger a new routing event
if self.ports_info[thesrc]["fifo_in_event"].val:
self.debug("-> recv: CATCH possible miss event because in port %d fifo_in_event=True", thesrc)
self.debug("-> recv: CATCH fifo_in_event list %s" % repr(self.list_fifo_in_events))
self.ports_info[thesrc]["fifo_in_event"].next = True
 
self.debug("-> recv returns 'noc_tlm_errcodes.no_error'")
return noc_tlm_errcodes.no_error
self.debug("-> recv returns 'noc_tbm_errcodes.no_error'")
return noc_tbm_errcodes.no_error
 
# ---------------------------
# Router code generation model
 
class basic_router_codegen(noc_codegen_ext):
"""
Code generation extension for Router objects.
"""
def __init__(self, codegen_ref):
noc_codegen_ext.__init__(self, codegen_ref)
self.router_ref = codegen_ref.nocobject_ref
if not isinstance(self.router_ref, router):
raise TypeError("Argument must be a 'noc_codegen_base' instance defined for a router object.")
 
# router model: This basic router has some parameters put in the
# generics list, and a fixed number of NoC ports: 4.
# assumptions: use 4 ports 'dualwb_intercon' plus 1 port 'slavewb_intercon'
codegen_ref.modulename = "basic_4P_router"
# 1. convert basic attributes to generics
codegen_ref.add_generic("name", self.router_ref.name, "Router Name")
codegen_ref.add_generic("address", self.router_ref.address, "Router Address")
# assuming rectangular layout
codegen_ref.add_generic("coord_x", self.router_ref.coord_x, "Router X-axis Coord")
codegen_ref.add_generic("coord_y", self.router_ref.coord_y, "Router Y-axis Coord")
# 2. Calculate which of 4 ports is used by who
portinfo = {"N": None, "E": None, "S": None, "W": None}
for pname, pvalues in self.router_ref.ports.iteritems():
if pname != self.router_ref.address:
# check correct intercon
if not isinstance(pvalues["channel"].ports[self.router_ref.address]["intercon"], dualwb_intercon):
raise UserWarning("Port '%d' on router '%s' does not use intercon 'dualwb_intercon'." % (pname, self.router_ref.name))
# calculate which port
dx = self.router_ref.coord_x - pvalues["peer"].coord_x
dy = self.router_ref.coord_y - pvalues["peer"].coord_y
if dx == 0:
if dy > 0:
portinfo["S"] = pname
else:
portinfo["N"] = pname
if dy == 0:
if dx > 0:
portinfo["W"] = pname
else:
portinfo["E"] = pname
else:
# check correct intercon
if not isinstance(pvalues["channel"].ports[self.router_ref.address]["intercon"], slavewb_intercon):
raise UserWarning("Port 'Local' on router '%s' does not use intercon 'slavewb_intercon'." % self.router_ref.name)
icon_ref = dualwb_intercon()
# 3. Add ports and info through generics
for pname, pvalue in portinfo.iteritems():
# add new port
pstr = "Port%s" % pname
codegen_ref.add_port(pstr, None, "Port %s" % pname, type=icon_ref.intercon_type, nocport=pvalue)
for signame, sigval in icon_ref.signals.iteritems():
stmp = get_new_signal(
name=signame,
direction=sigval["direction"],
default_value=intbv(0)[sigval["width"]:],
description=sigval["description"])
codegen_ref.add_port(pstr, stmp)
# determine if the port is used
if pvalue is None:
penable = 0
paddr = 0
else:
penable = 1
paddr = pvalue
codegen_ref.add_generic("Use_Port%s" % pname, penable, "Is Port%s being used?" % pname)
codegen_ref.add_generic("Dest_Port%s" % pname, paddr, "Dest address in Port%s" % pname)
# 4. Local port
icon_ref = slavewb_intercon()
codegen_ref.add_port("PortLocal", None, "Port Local", type=icon_ref.intercon_type)
for signame, sigval in icon_ref.signals.iteritems():
stmp = get_new_signal(
name=signame,
direction=sigval["direction"],
default_value=intbv(0)[sigval["width"]:],
description=sigval["description"])
codegen_ref.add_port("PortLocal", stmp)
# 5. Calculate a hash with generics and ports info. This hash will help
# codegen to establish equivalent router implementations.
codegen_ref.model_hash()
 
# 6. Implementation comment
codegen_ref.implementation += "-- Add here implementation code for Router %s" % self.router_ref.name
/nocmodel/trunk/nocmodel/basicmodels/intercon_model.py
0,0 → 1,231
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# Intercon models
# * Dual P2P Wishbone model
# * Single Bus Wishbone model
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 11-03-2011
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 11-03-2011 : (OD) initial release
#
 
"""
Basic Wishbone intercon models
"""
 
from nocmodel import *
 
class dualwb_intercon(intercon):
"""
Wishbone dual P2P intercon model
This intercon defines two bidirectional Wishbone P2P ports.
"""
intercon_type = "dualwb"
complement = None
sideinfo = ""
def __init__(self, **kwargs):
intercon.__init__(self, **kwargs)
# attributes: data_width (default 32 bits)
if not hasattr(self, "data_width"):
setattr(self, "data_width", 32)
# addr_width (default 0, don't use address signal)
if not hasattr(self, "addr_width"):
setattr(self, "addr_width", 0)
 
self.intercon_type = "dualwb"
# self.complement = None
# self.sideinfo = ""
# build the intercon structure
# Common signals
#self.signals["rst_i"]
#self.signals["clk_i"]
# Master part
# discard m_dat_i, m_we_o, m_sel_o, m_rty_i, m_lock_o
# optional m_adr_o
self.signals["m_dat_o"] = {"width": self.data_width, "direction": "out", "signal_obj": None, "description": "Master data output"}
if self.addr_width > 0:
self.signals["m_adr_o"] = {"width": self.addr_width, "direction": "out", "signal_obj": None, "description": "Master address output"}
self.signals["m_stb_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Master strobe"}
self.signals["m_cyc_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Master cycle"}
self.signals["m_lflit_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Master last flit flag"}
self.signals["m_ack_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Master acknowledge"}
self.signals["m_stall_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Master stall"}
self.signals["m_err_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Master error"}
# Slave part
# discard s_adr_i, s_dat_o, s_we_i, s_sel_i, s_rty_o, s_lock_i
self.signals["s_dat_i"] = {"width": self.data_width, "direction": "in", "signal_obj": None, "description": "Slave data input"}
if self.addr_width > 0:
self.signals["s_adr_i"] = {"width": self.addr_width, "direction": "in", "signal_obj": None, "description": "Slave address input"}
self.signals["s_stb_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Slave strobe"}
self.signals["s_cyc_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Slave cycle"}
self.signals["s_lflit_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Slave last flit flag"}
self.signals["s_ack_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Slave acknowledge"}
self.signals["s_stall_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Slave stall"}
self.signals["s_err_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Slave error"}
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.
"""
if signalname not in self.signals:
raise KeyError("Signal '%s' not found" % signalname)
mchange = {"m": "s", "s": "m"}
dchange = {"i": "o", "o": "i"}
return mchange[signalname[0]] + signalname[1:-1] + dchange[signalname[-1]]
class slavewb_intercon():
pass
 
class masterwb_intercon(intercon):
"""
Wishbone single bus master intercon model
This intercon defines a simple master Wishbone bus.
"""
intercon_type = "masterwb"
complement = slavewb_intercon
sideinfo = "master"
def __init__(self, **kwargs):
intercon.__init__(self, **kwargs)
# attributes: data_width (default 32 bits)
if not hasattr(self, "data_width"):
setattr(self, "data_width", 32)
# addr_width (default 16 bits)
if not hasattr(self, "addr_width"):
setattr(self, "addr_width", 16)
self.intercon_type = "masterwb"
# self.complement = slavewb_intercon
# self.sideinfo = "master"
# build the intercon structure
self.signals["rst_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Reset input"}
self.signals["clk_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Clock input"}
# discard m_sel_o, m_rty_i, m_lock_o
self.signals["m_adr_o"] = {"width": self.addr_width, "direction": "out", "signal_obj": None, "description": "Master address output"}
self.signals["m_dat_i"] = {"width": self.data_width, "direction": "in", "signal_obj": None, "description": "Master data input"}
self.signals["m_dat_o"] = {"width": self.data_width, "direction": "out", "signal_obj": None, "description": "Master data output"}
self.signals["m_we_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Master write enable"}
self.signals["m_stb_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Master strobe"}
self.signals["m_cyc_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Master cycle"}
self.signals["m_ack_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Master acknowledge"}
self.signals["m_stall_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Master stall"}
self.signals["m_err_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Master error"}
self.signals["m_irq_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Master IRQ"}
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.
"""
if signalname not in self.signals:
raise KeyError("Signal '%s' not found" % signalname)
mchange = {"m": "s", "s": "m"}
dchange = {"i": "o", "o": "i"}
if signalname == "rst_i" or signalname == "clk_i":
# special signals. Return None
return None
else:
return mchange[signalname[0]] + signalname[1:-1] + dchange[signalname[-1]]
class slavewb_intercon(intercon):
"""
Wishbone single bus slave intercon model
This intercon defines a simple slave Wishbone bus.
"""
intercon_type = "slavewb"
complement = masterwb_intercon
sideinfo = "slave"
def __init__(self, **kwargs):
intercon.__init__(self, **kwargs)
# attributes: data_width (default 32 bits)
if not hasattr(self, "data_width"):
setattr(self, "data_width", 32)
# addr_width (default 16 bits)
if not hasattr(self, "addr_width"):
setattr(self, "addr_width", 16)
self.intercon_type = "slavewb"
# self.complement = masterwb_intercon
# self.sideinfo = "slave"
# build the intercon structure
self.signals["rst_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Reset input"}
self.signals["clk_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Clock input"}
# discard s_sel_o, s_rty_i, s_lock_o
self.signals["s_adr_i"] = {"width": self.addr_width, "direction": "in", "signal_obj": None, "description": "Slave address output"}
self.signals["s_dat_o"] = {"width": self.data_width, "direction": "out", "signal_obj": None, "description": "Slave data input"}
self.signals["s_dat_i"] = {"width": self.data_width, "direction": "in", "signal_obj": None, "description": "Slave data output"}
self.signals["s_we_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Slave write enable"}
self.signals["s_stb_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Slave strobe"}
self.signals["s_cyc_i"] = {"width": 1, "direction": "in", "signal_obj": None, "description": "Slave cycle"}
self.signals["s_ack_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Slave acknowledge"}
self.signals["s_stall_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Slave stall"}
self.signals["s_err_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Slave error"}
self.signals["s_irq_o"] = {"width": 1, "direction": "out", "signal_obj": None, "description": "Slave IRQ"}
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.
"""
if signalname not in self.signals:
raise KeyError("Signal '%s' not found" % signalname)
mchange = {"m": "s", "s": "m"}
dchange = {"i": "o", "o": "i"}
if signalname == "rst_i" or signalname == "clk_i":
# special signals. Return None
return None
else:
return mchange[signalname[0]] + signalname[1:-1] + dchange[signalname[-1]]
/nocmodel/trunk/nocmodel/basicmodels/basic_ipcore.py
3,11 → 3,12
 
#
# Basic IPcore model
# * TLM model
# * TBM model
# * Code generation model
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 03-03-2011
# Version: 0.2
# Date: 14-03-2011
 
#
# This code is free software; you can redistribute it and/or
30,20 → 31,24
# Changelog:
#
# 03-03-2011 : (OD) initial release
# 14-03-2011 : (OD) adding code generation model
#
 
"""
Basic ipcore TLM model
* Basic ipcore TBM model
* Ipcore code generation model
"""
 
from nocmodel.noc_tlm_base import *
from nocmodel.noc_tbm_base import *
from nocmodel.noc_codegen_base import *
from intercon_model import *
 
# ---------------------------
# Basic IPCore TLM model
# Basic IPCore TBM model
 
class basic_ipcore_tlm(noc_tlm_base):
class basic_ipcore_tbm(noc_tbm_base):
"""
TLM model of a NoC ipcore. Its based on sending and receiving packets
TBM model of a NoC ipcore. Its based on sending and receiving packets
to a custom-based MyHDL generators. This class does not define any
functionality.
55,7 → 60,7
* See code comments to better understanding.
"""
def __init__(self, ipcore_ref):
noc_tlm_base.__init__(self)
noc_tbm_base.__init__(self)
if isinstance(ipcore_ref, ipcore):
self.ipcore_ref = ipcore_ref
self.graph_ref = ipcore_ref.graph_ref
67,6 → 72,8
self.debug("constructor")
# generic parameters
self.retrytimes = 3
self.retrydelay = 2
 
# one-port support: get a reference to the related channel
self.localch = self.ipcore_ref.channel_ref
87,7 → 94,12
def outgoing_process():
while True:
yield self.outgoing_packet
retval = self.send(self.ipcore_ref, self.localch, self.outgoing_packet.val)
# multiple tries
for i in range(self.retrytimes):
retval = self.send(self.ipcore_ref, self.localch, self.outgoing_packet.val)
if retval == noc_tbm_errcodes.no_error:
break;
yield myhdl.delay(self.retrydelay)
self.generators = [outgoing_process]
self.debugstate()
102,7 → 114,7
Notes:
* This method requires that genfunction has the following prototype:
* my_function(din, dout, tlm_ref, <other_arguments>)
* my_function(din, dout, tbm_ref, <other_arguments>)
* din is a MyHDL Signal of type packet, and is the input signal
to the ipcore. Use this signal to react to input events and
receive input packets.
109,12 → 121,12
* dout is a MyHDL Signal of type packet, and is the output
signal to the ipcore. Use this signal to send out packets to
local channel (and then insert into the NoC).
* tlm_ref is a reference to this object. Normal use is to access
logging methods (e.g. tlm_ref.info("message") ).
* tbm_ref is a reference to an object with logging methods.
(e.g. tbm_ref.info("message") ).
* <other_arguments> may be defined, this method use kwargs
argument to pass them.
"""
makegen = genfunction(din=self.incoming_packet, dout=self.outgoing_packet, tlm_ref=self, **kwargs)
makegen = genfunction(din=self.incoming_packet, dout=self.outgoing_packet, tbm_ref=self, **kwargs)
self.debug("register_generator( %s ) generator is %s args %s" % (repr(genfunction), repr(makegen), repr(kwargs)))
self.generators.append(makegen)
 
131,7 → 143,7
self.debug("-> send( %s , %s , %s , %s )" % (repr(src), repr(dest), repr(packet), repr(addattrs)))
 
# call recv on the local channel object
retval = self.localch.tlm.recv(self.ipcore_ref, self.localch, packet, addattrs)
retval = self.localch.tbm.recv(self.ipcore_ref, self.localch, packet, addattrs)
# something to do with the retval? Only report it.
self.debug("-> send returns code '%s'" % repr(retval))
150,5 → 162,63
# update signal
self.incoming_packet.next = packet
 
self.debug("-> recv returns 'noc_tlm_errcodes.no_error'")
return noc_tlm_errcodes.no_error
self.debug("-> recv returns 'noc_tbm_errcodes.no_error'")
return noc_tbm_errcodes.no_error
 
# ---------------------------
# Ipcore code generation model
 
class basic_ipcore_codegen(noc_codegen_ext):
"""
Code generation extension for Ipcore objects.
"""
def __init__(self, codegen_ref):
noc_codegen_ext.__init__(self, codegen_ref)
#self.codegen_ref = codegen_ref
self.ipcore_ref = codegen_ref.nocobject_ref
if not isinstance(self.ipcore_ref, ipcore):
raise TypeError("Argument must be a 'noc_codegen_base' instance defined for a ipcore object.")
 
# ipcore model: This basic ipcore has some parameters put in the
# generics list, and only one port of type masterwb.
codegen_ref.modulename = "basic_ipcore"
# 1. convert some attributes to generics
codegen_ref.add_generic("name", self.ipcore_ref.name, "Ipcore Name")
codegen_ref.add_generic("address", self.ipcore_ref.router_ref.address, "Ipcore router Address")
# 2. check intercon on ipcore port
ch = self.ipcore_ref.channel_ref
icon = ch.ports[None]["intercon"]
if not isinstance(icon, masterwb_intercon):
raise UserWarning("Port Local on ipcore '%s' does not use intercon 'masterwb_intercon'." % self.ipcore_ref.name)
# 2. convert ipcore port to codegen port
codegen_ref.add_port("PortLocal", None, "Port Local", type=icon.intercon_type)
for signame, sigval in icon.signals.iteritems():
stmp = get_new_signal(
name=signame,
direction=sigval["direction"],
default_value=intbv(0)[sigval["width"]:],
description=sigval["description"])
codegen_ref.add_port("PortLocal", stmp)
# 3. Calculate a Hash with generics and ports info.
# WARNING: You must recalculate the hash when you change the model!
codegen_ref.model_hash()
# 4. Implementation comment
codegen_ref.implementation += "-- Add here implementation code for Ipcore %s" % self.ipcore_ref.name
def add_external_signal(self, name, direction, value, description="", **kwargs):
"""
Wrapper to noc_codegen_base.add_external_signal method, to support hash
updating.
"""
retval = self.codegen_ref.add_external_signal(name, direction, value, description, **kwargs)
self.codegen_ref.model_hash()
return retval
/nocmodel/trunk/nocmodel/basicmodels/basic_noc_codegen.py
0,0 → 1,229
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# Basic NoC Code generation model
# * VHDL code support
#
# Author: Oscar Diaz
# Version: 0.2
# Date: 14-03-2011
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 14-03-2011 : (OD) initial release
#
 
"""
* Basic NoC VHDL code generation model
"""
 
from nocmodel import *
from nocmodel.noc_codegen_base import *
from nocmodel.noc_codegen_vhdl import *
from intercon_model import *
 
from myhdl import intbv
 
class basic_noc_arch_vhdl(noc_codegen_ext):
"""
Code generation extension for NoC objects in VHDL.
This extension object generates the architecture needed to connect all
objects into a top VHDL file.
"""
def __init__(self, codegen_ref):
noc_codegen_ext.__init__(self, codegen_ref)
self.noc_ref = codegen_ref.nocobject_ref
if not isinstance(self.noc_ref, noc):
raise TypeError("Argument must be a 'noc_codegen_base' instance defined for a NoC object.")
codegen_ref.modulename = self.noc_ref.name
# NoC model: must generate all needed components and join them together
# in this top module.
 
# 1. convert some attributes to generics
codegen_ref.add_generic("name", self.noc_ref.name, "NoC Name")
# 2. define a basic port signals:
codegen_ref.add_external_signal("rst_i", "in", intbv(0)[1:], "System reset in")
codegen_ref.add_external_signal("clk_i", "in", intbv(0)[1:], "System clock in")
# 2. keep a list of needed components
hash_list = {}
# 2. search for defined external_ports in codegen objects
for obj in self.noc_ref.all_list(True):
for sig in obj.codegen.external_signals:
# make a copy of the signal dict, adding a reference to the
# nocobject which belongs
csig = sig.copy()
csig["back_ref"] = obj
codegen_ref.external_signals.append(csig)
# 3. Build implementation string
codegen_ref.implementation += "-- Implementation for '%s' name '%s' generated by '%s'\n" % (repr(self.noc_ref), self.noc_ref.name, repr(self))
# 3.1 add components
# TODO: check the components name
for obj in self.noc_ref.all_list():
# add only for routers and ipcores (WARNING)
if isinstance(obj, (router, ipcore)):
if obj.codegen.interface_hash == "":
# update hash
obj.codegen.model_hash()
# check if the component is already declared
if hash(obj.codegen.interface_hash) in hash_list:
# already declared component
hash_list[hash(obj.codegen.interface_hash)]["instance_list"].append(obj)
else:
# new component
codegen_ref.implementation += "\n-- Component for '%s' name '%s'\n" % (repr(obj), obj.name)
codegen_ref.implementation += obj.codegen.generate_component()
hash_list[hash(obj.codegen.interface_hash)] = {
"str_hash": obj.codegen.interface_hash,
"component_name": obj.codegen.modulename,
"instance_list": [obj]
}
# 3.2 intermediate signals
codegen_ref.implementation += "\n-- Intermediate signals\n\n"
# signals here has the format: "sig_<obj.name>_<signal_name>"
for obj in self.noc_ref.all_list():
# add only for routers and ipcores (WARNING)
if isinstance(obj, (router, ipcore)):
for s in obj.codegen.generate_port_declaration(None, True):
if s[0:2] != "--":
# note that port declaration will put "in" or "out". Filter it
sf = s.replace(": in", ":").replace(": out", ":")
codegen_ref.implementation += "signal sig_%s_%s;\n" % (obj.name, sf)
else:
codegen_ref.implementation += "-- Object %s : %s\n" % (obj.name, s[2:])
codegen_ref.implementation += "begin\n"
codegen_ref.implementation += codegen_ref.add_tab("-- component instantiation\n\n")
# 3.3 instances and port mapping
# hash_list has the declared components and its related objects
for hcomp in hash_list.itervalues():
for obj in hcomp["instance_list"]:
codegen_ref.implementation += codegen_ref.add_tab("-- Instance for '%s' name '%s'\n" % (repr(obj), obj.name))
codegen_ref.implementation += codegen_ref.add_tab("i_%s : %s" % (obj.name, hcomp["component_name"]))
# generic map
if len(obj.codegen.generics) > 0:
codegen_ref.implementation += " generic map (\n"
strl = []
for g in obj.codegen.generics:
strl.append("%s => %s" % (g["name"], convert_value(g["default_value"], g["type"])))
codegen_ref.implementation += ",\n".join(codegen_ref.add_tab(strl, 2))
codegen_ref.implementation += codegen_ref.add_tab("\n)")
# port map
if (len(obj.codegen.ports) + len(obj.codegen.external_signals)) > 0:
codegen_ref.implementation += " port map (\n"
strl = []
for p in obj.codegen.ports:
# search for each signal in a port
for sig in p["signal_list"]:
# format: <portname>_<signame> => sig_<obj.name>_<portname>_<signal_name>
strl.append("%s_%s => sig_%s_%s_%s" % (p["name"], sig["name"], obj.name, p["name"], sig["name"]))
# and then in external_signals
for sig in obj.codegen.external_signals:
# format: <signame> => <obj.name>_<signal_name>
strl.append("%s => %s_%s" % (sig["name"], obj.name, sig["name"]))
codegen_ref.implementation += ",\n".join(codegen_ref.add_tab(strl, 2))
codegen_ref.implementation += codegen_ref.add_tab("\n)")
codegen_ref.implementation += ";\n\n"
# 3.4 signal connections
# connect routers first
for obj in self.noc_ref.router_list():
# go through all ports and check its use
codegen_ref.implementation += codegen_ref.add_tab("-- Signal mapping for '%s' name '%s'\n" % (repr(obj), obj.name))
for p in obj.codegen.ports:
if p["type"] == "dualwb":
if p["nocport"] is None:
codegen_ref.implementation += codegen_ref.add_tab("-- port '%s' unused\n" % p["name"])
# Unused port. Go through all signals and put input
# values tied to 0
for sig in p["signal_list"]:
if sig["direction"] == "in":
# format: sig_<obj.name>_<portname>_<signal_name>
codegen_ref.implementation += codegen_ref.add_tab("sig_%s_%s_%s <= %s;\n" % (obj.name, p["name"], sig["name"], convert_value(sig["default_value"], sig["type"])))
else:
# connected with a port. Assign only input signals.
peerobj = obj.ports[p["nocport"]]["peer"]
# search for peer object codegen ports
peerpname = None
for peerp in peerobj.codegen.ports:
if peerp["nocport"] is not None:
findobj = peerobj.ports[peerp["nocport"]]["peer"]
if findobj == obj:
peerpname = peerp["name"]
break
if peerpname is None:
raise ValueError("Connected object '%s'->'%s': port not found" % (obj.name, peerobj.name))
codegen_ref.implementation += codegen_ref.add_tab("-- port '%s' connected to object '%s' port '%s'\n" % (p["name"], peerobj.name, peerpname))
for sig in p["signal_list"]:
if sig["direction"] == "in":
peersig = obj.ports[p["nocport"]]["channel"].ports[obj.address]["intercon"].get_complement_signal(sig["name"])
if peersig is not None:
# format: sig_<obj.name>_<portname>_<signal_name>
codegen_ref.implementation += codegen_ref.add_tab("sig_%s_%s_%s <= sig_%s_%s_%s;\n" % (obj.name, p["name"], sig["name"], peerobj.name, peerpname, peersig))
else:
codegen_ref.implementation += codegen_ref.add_tab("-- Special signal sig_%s_%s_%s not assigned yet.\n" % (obj.name, p["name"], sig["name"]))
# then ipcores
for obj in self.noc_ref.ipcore_list():
codegen_ref.implementation += codegen_ref.add_tab("-- Signal mapping for '%s' name '%s'\n" % (repr(obj), obj.name))
# connect signals from and to ipcore
# get local and remote intercon
obj_icon = obj.ports[obj.get_address()]["channel"].ports[None]["intercon"]
dest_icon = obj.ports[obj.get_address()]["channel"].ports[obj.get_address()]["intercon"]
obj_port = obj.codegen.ports[0]
dest_port = None
for p in obj.router_ref.codegen.ports:
if p["type"] == dest_icon.intercon_type:
dest_port = p
if dest_port is None:
raise ValueError("Router object '%s': local port not found" % obj.router_ref.name)
codegen_ref.implementation += codegen_ref.add_tab("-- port '%s' connected to object '%s' port '%s'\n" % (p["name"], obj.router_ref.name, dest_port["name"]))
# first ipcore <= router
for sig in obj_port["signal_list"]:
if sig["direction"] == "in":
peersig = obj_icon.get_complement_signal(sig["name"])
if peersig is not None:
# format: sig_<obj.name>_<portname>_<signal_name>
codegen_ref.implementation += codegen_ref.add_tab("sig_%s_%s_%s <= sig_%s_%s_%s;\n" % (obj.name, obj_port["name"], sig["name"], obj.router_ref.name, dest_port["name"], peersig))
else:
# special port (TODO!)
codegen_ref.implementation += codegen_ref.add_tab("-- Special signal sig_%s_%s_%s not assigned yet.\n" % (obj.name, obj_port["name"], sig["name"]))
# then router <= ipcore
for sig in dest_port["signal_list"]:
if sig["direction"] == "in":
peersig = dest_icon.get_complement_signal(sig["name"])
if peersig is not None:
# format: sig_<obj.name>_<portname>_<signal_name>
codegen_ref.implementation += codegen_ref.add_tab("sig_%s_%s_%s <= sig_%s_%s_%s;\n" % (obj.router_ref.name, dest_port["name"], sig["name"], obj.name, obj_port["name"], peersig))
else:
codegen_ref.implementation += codegen_ref.add_tab("-- Special signal sig_%s_%s_%s not assigned yet.\n" % (obj.router_ref.name, dest_port["name"], sig["name"]))
codegen_ref.implementation += codegen_ref.add_tab("-- Implementation code for Noc --")
/nocmodel/trunk/nocmodel/__init__.py
5,8 → 5,8
# NoCmodel package
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 03-03-2011
# Version: 0.2
# Date: 05-07-2012
 
#
# This code is free software; you can redistribute it and/or
29,6 → 29,7
# Changelog:
#
# 03-03-2011 : (OD) initial release
# 14-03-2011 : (OD) support for code generation
#
 
"""
40,8 → 41,11
* Module noc_base: NoCmodel Base Objects
* Module noc_guilib: NoCmodel Graphic utilities
* Module noc_tlm_base: NoCmodel TLM simulation support
* Module noc_tlm_utils: helper functions for TLM simulation
* Module noc_tbm_base: NoCmodel TBM simulation support
* Module noc_tbm_utils: helper functions for TBM simulation
* Module noc_codegen_base: NoCmodel base for code generation support
* Module noc_codegen_vhdl: VHDL support for code generation
* Module noc_helpers: Utility functions
* Package basicmodels: basic examples of NoC objects (not imported by default)
"""
 
51,7 → 55,11
# provided modules
from noc_base import *
from noc_guilib import *
from noc_tlm_base import *
from noc_tlm_utils import *
from noc_tbm_base import *
from noc_tbm_utils import *
from noc_rtl_myhdl import *
from noc_codegen_base import *
from noc_codegen_vhdl import *
from noc_helpers import *
 
__version__ = "0.1"
__version__ = "0.2"
/nocmodel/trunk/nocmodel/noc_codegen_vhdl.py
0,0 → 1,636
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# NoC Code generator - VHDL generator
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 11-11-2011
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 11-11-2011 : (OD) initial release
#
 
"""
Code generation support for VHDL
 
This module defines:
* Class 'noc_codegen_vhdl'
* Function 'add_codegen_vhdl_support'
"""
 
from nocmodel import *
from noc_codegen_base import *
from myhdl import intbv, bin
 
class noc_codegen_vhdl(noc_codegen_base):
"""
VHDL generator class
This class defines methods used to generate VHDL code from any noc object.
Like base class, this object has this base attributes:
* docheader
* libraries
* modulename
* generics
* ports
* implementation
"""
def __init__(self, nocobject_ref, **kwargs):
noc_codegen_base.__init__(self, nocobject_ref, **kwargs)
# note: the noc object must be complete, in order to
# add code generation support
#self.nocobject_ref = nocobject_ref
self.modulename = self.to_valid_str(self.nocobject_ref.name)
# default header and libraries
self.docheader = "-- Document header"
self.libraries = "library ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;"
 
# code generation attributes
self.usetab = " " # 4-space tabs
self.full_comments = True
# main methods
def generate_file(self):
"""
Generate the entire file that implements this object.
"""
# Unless code generation is externally generated.
if self.external_conversion:
# use "codemodel" object on nocobject_ref
if hasattr(self.nocobject_ref, "codemodel"):
return self.nocobject_ref.codemodel.generate_file()
else:
raise AttributeError("External conversion flag is enabled, but there's no 'codemodel' object available in nocobject %s" % self.nocobject_ref)
else:
# first try to call build_implementation() method
self.build_implementation()
sret = self.docheader + "\n\n" + self.libraries + "\n\n"
if self.full_comments:
sret += self.make_comment("Object '%s' name '%s' description '%s'\n" % (repr(self.nocobject_ref), self.nocobject_ref.name, self.nocobject_ref.description))
sret += self.generate_entity_section() + "\n\n"
sret += self.generate_architecture_section() + "\n"
return sret
def generate_component(self):
"""
Generate a component definition for this object.
"""
sret = "component %s\n" % self.modulename
stmp = self.generate_generics_section()
if stmp != "":
sret += self.add_tab(stmp) + ";\n"
stmp = self.generate_ports_section()
if stmp != "":
sret += self.add_tab(stmp) + ";\n"
sret += "end component;\n"
return sret
 
def generate_generic_declaration(self, generic=None, with_default=False):
"""
Generate a generic declaration for this object.
Arguments:
* generic : either a name or a list index for a particular generic
* with_default : True to add the default value
Returns:
* A string when generic argument is used
* A list of strings with all generics
"""
if generic is None:
# all generics
l = []
for i in range(len(self.generics)):
l.append(self.generate_generic_declaration(i, with_default))
return l
else:
# search for correct index
if isinstance(generic, int):
g = self.generics[generic]
elif isinstance(generic, string):
g = filter(lambda s: s["name"] == generic, self.generics)[0]
else:
raise TypeError("Don't know how to search with '%s'." % repr(generic))
sret = "%s : %s" % (self.to_valid_str(g["name"]), g["type"])
if with_default:
sret += ' := %s' % convert_value(g["default_value"], g["type"], g["type_array"])
# add string quotes
# if g["type"] == "string":
# sret += ' := "%s"' % g["default_value"]
# else:
# sret += ' := %s' % g["default_value"]
return sret
 
def generate_port_declaration(self, port=None, with_default=False):
"""
Generate a port declaration for this object.
Arguments:
* port : either a name or a list index for a particular port
* with_default : True to add the default value
Returns:
* A list of strings with all signals in port when port argument is used
* A list of strings with all signals in all ports
"""
if port is None:
# all ports
l = []
for i in range(len(self.ports)):
l.append(self.make_comment("Port '%s' : '%s'" % (self.to_valid_str(self.ports[i]["name"]), self.ports[i]["type"])))
pl = self.generate_port_declaration(i, with_default)
pl.sort()
l.extend(pl)
return l
else:
# search for correct index
if isinstance(port, int):
idx = port
elif isinstance(port, string):
p = filter(lambda s: s["name"] == port, self.ports)[0]
idx = self.ports.index(p)
else:
raise TypeError("Don't know how to search with '%s'." % repr(port))
return self.generate_signal_declaration(idx, None, with_default)
 
def generate_signal_declaration(self, inport=None, signal=None, with_default=False):
"""
Generate a signal declaration for this object.
Arguments:
* inport : either a name or a list index for a particular port. None
means use the external_signals list
* signal : either a name or a list index for a particular signal
* with_default : True to add the default value
Returns:
* A string when signal argument is used
* A list of strings with all signals
"""
if signal is None:
# all signals
l = []
if inport is None:
r = range(len(self.external_signals))
else:
# what port?
if isinstance(inport, int):
g = self.ports[inport]
elif isinstance(inport, string):
g = filter(lambda s: s["name"] == inport, self.ports)[0]
else:
raise TypeError("Don't know how to search with '%s'." % repr(inport))
r = range(len(g["signal_list"]))
for i in r:
l.append(self.generate_signal_declaration(inport, i, with_default))
return l
else:
# locate either port or external_signals
if inport is None:
if isinstance(signal, int):
sig = self.external_signals[signal]
elif isinstance(signal, string):
sig = filter(lambda s: s["name"] == signal, self.external_signals)[0]
else:
raise TypeError("Don't know how to search with '%s'." % repr(signal))
# put nothing as signal prefix
sprefix = ""
else:
# what port?
if isinstance(inport, int):
p = self.ports[inport]
elif isinstance(inport, string):
p = filter(lambda s: s["name"] == inport, self.ports)[0]
else:
raise TypeError("Don't know how to search with '%s'." % repr(inport))
# what signal?
if isinstance(signal, int):
sig = p["signal_list"][signal]
elif isinstance(signal, string):
sig = filter(lambda s: s["name"] == signal, p["signal_list"])[0]
else:
raise TypeError("Don't know how to search with '%s'." % repr(signal))
# put port name as signal prefix
#sprefix = self.to_valid_str(p["name"]) + "_"
sprefix = ""
sret = "%s%s : %s %s" % (sprefix, self.to_valid_str(sig["name"]), sig["direction"], sig["type"])
if with_default:
sret += ' := %s' % convert_value(sig["default_value"], sig["type"])
# if sig["type"] == "string":
# sret += ' := "%s"' % sig["default_value"]
# else:
# sret += ' := %s' % sig["default_value"]
return sret
def make_comment(self, data):
"""
Convert string data to language comment
Argument:
* data: string or list of strings to convert
Returns: a new string or list of strings with comments added.
"""
if isinstance(data, str):
return "-- %s%s" % (data[:-1].replace("\n", "\n-- "), data[-1])
else:
# don't put exception catch. It is an error if data is not
# iterable.
it = iter(data)
retval = []
for s in data:
retval.append("-- %s%s" % (s[:-1].replace("\n", "\n-- "), s[-1]))
return retval
def add_tab(self, data, level=1):
"""
Add an indentation level to the string
Argument:
* data: string or list of strings
* level: how many indentation levels to add. Default 1
Returns: string or list of strings with <level> indentation levels.
"""
leveltabs = self.usetab*level
if isinstance(data, str):
return "%s%s%s" % (leveltabs, data[:-1].replace("\n", "\n%s" % leveltabs), data[-1])
else:
# don't put exception catch. It is an error if data is not
# iterable.
it = iter(data)
retval = []
for s in data:
retval.append("%s%s%s" % (leveltabs, s[:-1].replace("\n", "\n%s" % leveltabs), s[-1]))
return retval
def to_valid_str(self, str_in):
"""
Convert an input string, changing special characters used on
the HDL language. Useful for set names .
Argument:
* str_in: string to convert
Returns: the converted string.
"""
# list of transformations:
# * strip spaces
# * space,":" with "_"
s = str_in.strip()
s = s.replace(" ", "_")
s = s.replace(":", "_")
return s
 
# codegen model management
def add_generic(self, name, value, description="", **kwargs):
"""
Add a generic to the model - with VHDL type formatting.
"""
g = noc_codegen_base.add_generic(self, name, value, description, **kwargs)
# Set correct type. String by default
gadd = {"type": "string"}
if "type" in kwargs:
# Optional type must be a string with a custom type name.
if isinstance(kwargs["type"], str):
# custom type name.
gadd.update({"type": kwargs["type"]})
#else:
# default to use string
else:
gadd["type"] = self.calculate_type(value)
## use type in value
#gadd["type"] = _pytovhdltype[type(value)]
## defined range
#if "type_array" in kwargs:
#if isinstance(value, int):
## for an integer it means range
#gadd["type"] += " range %d to %d" % (kwargs["type_array"][0], kwargs["type_array"][1])
#elif isinstance(value, intbv):
## for a intbv it means bit boundaries
#gadd["type"] += "_vector(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
##else:
## ignore array range
#else:
## special case
#if isinstance(value, intbv):
## put vector only if necessary
#if value._nrbits > 1:
## extract vector information
#gadd["type_array"] = [0, value._nrbits - 1]
#gadd["type"] += "_vector(%d to %d)" % (0, value._nrbits - 1)
 
g.update(gadd)
return g
def add_port(self, name, signal_desc=None, description="", **kwargs):
"""
Add a port to the model - with VHDL type formatting.
"""
p = noc_codegen_base.add_port(self, name, signal_desc, description, **kwargs)
if signal_desc is None:
# nothing else to do
return p
# set correct type for the particular signal_desc
sig = filter(lambda x: x["name"] == signal_desc["name"], p["signal_list"])
if len(sig) == 0:
# strange error
raise ValueError("Strange error: recently added signal '%s' to port '%s', but signal cannot be found." % (signal_desc["name"], p["name"]))
else:
sig = sig[0]
# type inferring: only apply if signal_desc has empty type
if sig["type"] != "":
return p
# integer by default
sadd = {"type": "integer"}
if "type" in kwargs:
# Optional type must be a string with a custom type name.
if isinstance(kwargs["type"], str):
# custom type name.
sadd["type"] = kwargs["type"]
# also add if it has default_value
if "default_value" in kwargs:
sadd["default_value"] = kwargs["default_value"]
#else:
# default to use integer
else:
sadd["type"] = self.calculate_type(sig["default_value"])
## use type in value
#sadd["type"] = _pytovhdltype[type(sig["default_value"])]
## defined range
#if "type_array" in kwargs:
#if isinstance(sig["default_value"], int):
#sadd["type"] += " range(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
#elif isinstance(sig["default_value"], intbv):
#sadd["type"] += "_vector(%d downto %d)" % (kwargs["type_array"][1], kwargs["type_array"][0])
##else:
## ignore array range
#else:
## special case
#if isinstance(sig["default_value"], intbv):
## put vector only if necessary
#if sig["default_value"]._nrbits > 1:
## extract vector information
#sadd["type_array"] = [0, sig["default_value"]._nrbits - 1]
#sadd["type"] += "_vector(%d downto 0)" % (sig["default_value"]._nrbits - 1)
sig.update(sadd)
return p
def add_external_signal(self, name, direction, value, description="", **kwargs):
"""
Add a external signal to the model - with VHDL type formatting.
"""
sig = noc_codegen_base.add_external_signal(self, name, direction, value, description, **kwargs)
# Set correct type. integer by default
sadd = {"type": "integer"}
if "type" in kwargs:
# Optional type must be a string with a custom type name.
if isinstance(kwargs["type"], str):
# custom type name.
sadd.update({"type": kwargs["type"]})
#else:
# default to use integer
else:
sadd["type"] = self.calculate_type(value)
## use type in value
#sadd["type"] = _pytovhdltype[type(value)]
## defined range
#if "type_array" in kwargs:
#if isinstance(value, int):
#sadd["type"] += " range(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
#elif isinstance(value, intbv):
#sadd["type"] += "_vector(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
##else:
## ignore array range
#else:
## special case
#if isinstance(value, intbv):
## extract vector information
#sadd["type_array"] = [0, sig["default_value"]._nrbits - 1]
#if None not in sadd["type_array"]:
#sadd["type"] += "_vector(%d to %d)" % (0, sig["default_value"]._nrbits - 1)
sig.update(sadd)
return sig
# particular VHDL methods
def generate_entity_section(self):
"""
Generate entity section
"""
sret = "entity %s is\n" % self.modulename
stmp = self.generate_generics_section()
if stmp != "":
sret += self.add_tab(stmp) + ";\n"
stmp = self.generate_ports_section()
if stmp != "":
sret += self.add_tab(stmp) + ";\n"
sret += "end %s;\n" % self.modulename
return sret
def generate_architecture_section(self, archname="rtl"):
"""
Generate architecture section
"""
sret = "architecture %s of %s is\n" % (archname, self.modulename)
if self.implementation != "":
sret += self.add_tab(self.implementation)
sret += "\nend %s;\n" % archname
return sret
 
def generate_generics_section(self):
"""
Generate generics section used on entity and component
"""
sret = "generic (\n"
l = self.generate_generic_declaration(None, True)
if len(l) > 0:
l = self.add_tab(l)
sret += ";\n".join(l)
sret += "\n)"
else:
# empty generics section
sret = ""
return sret
def generate_ports_section(self):
"""
Generate ports section used on entity and component
"""
# first ports and then external signals
sret = "port (\n"
l = self.generate_port_declaration(None, False)
l.extend(self.generate_signal_declaration(None, None, False))
if len(l) > 0:
l = self.add_tab(l)
sret += ";\n".join(l)
sret += "\n)"
else:
# empty ports section
sret = ""
return sret
def calculate_type(self, object, with_default=False):
"""
Calculate the correct VHDL type for a particular object
Arguments:
* object:
* with_default: True to add a default value at the end
Returns:
A string with the VHDL equivalent type
"""
if isinstance(object, bool):
return "std_logic"
elif isinstance(object, (int, long)):
# CHECK if this is a correct type translation
return "integer"
elif isinstance(object, str):
return "string"
elif isinstance(object, myhdl.intbv):
width = object._nrbits
initval = object._val
elif isinstance(object, myhdl.SignalType):
width = object._nrbits
initval = object._init
else:
raise ValueError("Type conversion for object %s not found (type: %s)" % (repr(object), type(object)))
if width <= 0:
raise ValueError("Object %s don't have a valid bit width." % repr(object))
if width == 1:
retval = "std_logic"
defval = "'%d'" % int(initval)
else:
retval = "unsigned(%s downto 0)" % (width - 1)
defval = '"%s"' % myhdl.bin(initval, width)
if with_default:
return "%s := %s" % (retval, defval)
else:
return retval
# helper functions
def add_codegen_vhdl_support(instance, **kwargs):
"""
This function will add for every object in instance a noc_codegen object
"""
if isinstance(instance, noc):
# add code generation object
instance.codegen = noc_codegen_vhdl(instance, **kwargs)
# and add cg objects recursively
for obj in instance.all_list(True):
add_codegen_vhdl_support(obj, **kwargs)
elif isinstance(instance, (ipcore, router, channel)):
instance.codegen = noc_codegen_vhdl(instance, **kwargs)
else:
raise TypeError("Unsupported object: type %s" % type(instance))
def convert_value(data, custom_type=None, type_array=[None, None]):
"""
This function converts data to a string valid in VHDL syntax.
"""
retval = ""
numbits = 0
usedata = data
if custom_type is not None:
# custom type
if custom_type == int:
usedata = int(data)
elif custom_type == bool:
usedata = data == True
elif custom_type == intbv:
# need fixed boundaries. Use type_array
if type_array == [None, None]:
# default: one bit width
usedata = intbv(data)[1:]
else:
# intbv boundaries refer to bit width
usedata = intbv(data)[type_array[1]+1:type_array[0]]
elif custom_type == str:
usedata = str(data)
elif isinstance(custom_type, str):
# type in a string format
if custom_type == "integer":
usedata = int(data)
elif custom_type == "std_logic":
usedata = intbv(data)[1:]
elif custom_type == "string":
usedata = str(data)
elif custom_type.find("std_logic_vector") == 0:
# strip values
vecinfo = custom_type.replace("std_logic_vector", "").strip("()").split()
if vecinfo[1] == "to":
vecmin = int(vecinfo[0])
vecmax = int(vecinfo[2])
elif vecinfo[1] == "downto":
vecmin = int(vecinfo[2])
vecmax = int(vecinfo[0])
usedata = intbv(data)[vecmax+1:vecmin]
else:
raise TypeError("Unsupported custom type string '%s' for VHDL conversion." % custom_type)
else:
raise TypeError("Unsupported custom type '%s' for VHDL conversion." % type(custom_type))
# convert
if isinstance(usedata, int):
retval = "%d" % data
elif isinstance(usedata, bool):
retval = "'%d'" % int(data)
elif isinstance(usedata, intbv):
# check boundaries
if usedata._nrbits > 1:
# print vector in bits
retval = '"%s"' % bin(usedata, usedata._nrbits)
else:
retval = "'%d'" % usedata
elif isinstance(usedata, str):
retval = '"%s"' % usedata
else:
raise TypeError("Unsupported type '%s' for VHDL conversion." % type(usedata))
return retval
 
# helper structures:
# type conversions
_pytovhdltype = {
"bool": "std_logic",
"int": "integer",
"intbv" : "unsigned",
"str" : "string",
bool: "std_logic",
int: "integer",
intbv : "unsigned",
str : "string"
}
_pytovhdlzeroval = {
"bool": "False",
"int": "0",
"intbv" : '"0"',
"str" : '""',
bool: "False",
int: "0",
intbv : '"0"',
str : '""'
}
/nocmodel/trunk/nocmodel/noc_helpers.py
0,0 → 1,78
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# Helper functions for NoC Objects
# Functions that easily construct predefined NoC structures and objects
#
# Author: Oscar Diaz
# Version: 0.2
# Date: 14-03-2011
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 14-03-2011 : (OD) initial release
#
 
import networkx as nx
from noc_base import *
 
def generate_squarenoc(orderx=3, ordery=None, with_ipcore=False):
"""
NoC generator helper: generates a 2D grid NoC object
Arguments
* orderx: optional X-axis length of the grid. By default build a 3x3 square
grid.
* ordery: optional Y-axis length of the grid. By default build a square grid
of order "orderx". This argument is used to build rectangular grids.
* with_ipcore: If True, add ipcores to routers automatically.
"""
if ordery == None:
ordery = orderx
# 1. generate a 2d grid
basegrid = nx.grid_2d_graph(orderx, ordery)
# 2. convert to a graph with ints as nodes
convgrid = nx.Graph()
for n in basegrid.nodes_iter():
n2 = n[0] + n[1]*orderx
convgrid.add_node(n2, coord_x=n[0], coord_y=n[1])
for e in basegrid.edges_iter():
e1 = e[0][0] + e[0][1]*orderx
e2 = e[1][0] + e[1][1]*orderx
convgrid.add_edge(e1, e2)
nocbase = noc(name="NoC grid %dx%d" % (orderx, ordery), data=convgrid)
 
# 2. for each node add router object
for n in nocbase.nodes_iter():
cx = nocbase.node[n]["coord_x"]
cy = nocbase.node[n]["coord_y"]
r = nocbase._add_router_from_node(n, coord_x=cx, coord_y=cy)
if with_ipcore:
nocbase.add_ipcore(r)
# 3. for each edge add channel object
for e in nocbase.edges_iter():
nocbase._add_channel_from_edge(e)
return nocbase
/nocmodel/trunk/nocmodel/noc_tbm_utils.py
0,0 → 1,71
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# NoC TBM simulation support - Utilities
# This module declares additional helper functions
#
# Author: Oscar Diaz
# Version: 0.2
# Date: 17-03-2011
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 03-03-2011 : (OD) initial release
#
 
"""
=============================
NoCmodel TBM simulation utils
=============================
This module declares additional helper functions.
* Function 'add_tbm_basic_support'
"""
 
from noc_tbm_base import *
from nocmodel.basicmodels import *
 
# helper functions
def add_tbm_basic_support(instance, **kwargs):
"""
This function will add for every object in noc_instance a noc_tbm object
"""
if isinstance(instance, noc):
# add simulation object
instance.tbmsim = noc_tbm_simulation(instance, **kwargs)
# and add tbm objects recursively
for obj in instance.all_list():
altkwargs = kwargs
altkwargs.pop("log_file", None)
altkwargs.pop("log_level", None)
add_tbm_basic_support(obj, **kwargs)
elif isinstance(instance, ipcore):
instance.tbm = basic_ipcore_tbm(instance, **kwargs)
# don't forget internal channel
instance.channel_ref.tbm = basic_channel_tbm(instance.channel_ref, **kwargs)
elif isinstance(instance, router):
instance.tbm = basic_router_tbm(instance, **kwargs)
elif isinstance(instance, channel):
instance.tbm = basic_channel_tbm(instance, **kwargs)
else:
raise TypeError("Unsupported object: type %s" % type(instance))
/nocmodel/trunk/umldoc/basemodel.graphml
0,0 → 1,233
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yFiles for Java 2.8-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key attr.name="Description" attr.type="string" for="graph" id="d7">
<default/>
</key>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<node id="n0">
<data key="d4"/>
<data key="d5"><![CDATA[UMLClass]]></data>
<data key="d6">
<y:UMLClassNode>
<y:Geometry height="28.0" width="100.0" x="130.0" y="91.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="19.12646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.82666015625" x="18.086669921875" y="3.0">nx.Graph</y:NodeLabel>
<y:UML clipContent="true" constraint="" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel/>
<y:MethodLabel/>
</y:UML>
</y:UMLClassNode>
</data>
</node>
<node id="n1">
<data key="d4"/>
<data key="d5"><![CDATA[UMLClass]]></data>
<data key="d6">
<y:UMLClassNode>
<y:Geometry height="28.0" width="100.0" x="130.0" y="196.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="19.12646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="27.75927734375" x="36.120361328125" y="3.0">noc</y:NodeLabel>
<y:UML clipContent="true" constraint="" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel/>
<y:MethodLabel/>
</y:UML>
</y:UMLClassNode>
</data>
</node>
<node id="n2">
<data key="d4"/>
<data key="d5"><![CDATA[UMLClass]]></data>
<data key="d6">
<y:UMLClassNode>
<y:Geometry height="28.0" width="100.0" x="400.0" y="208.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="19.12646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="68.8095703125" x="15.59521484375" y="3.0">nocobject</y:NodeLabel>
<y:UML clipContent="true" constraint="" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel/>
<y:MethodLabel/>
</y:UML>
</y:UMLClassNode>
</data>
</node>
<node id="n3">
<data key="d4"/>
<data key="d5"><![CDATA[UMLClass]]></data>
<data key="d6">
<y:UMLClassNode>
<y:Geometry height="28.0" width="100.0" x="204.0" y="346.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="19.12646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="45.54541015625" x="27.227294921875" y="3.0">router</y:NodeLabel>
<y:UML clipContent="true" constraint="" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel/>
<y:MethodLabel/>
</y:UML>
</y:UMLClassNode>
</data>
</node>
<node id="n4">
<data key="d4"/>
<data key="d5"><![CDATA[UMLClass]]></data>
<data key="d6">
<y:UMLClassNode>
<y:Geometry height="28.0" width="100.0" x="340.0" y="406.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="19.12646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="56.01904296875" x="21.990478515625" y="3.0">channel</y:NodeLabel>
<y:UML clipContent="true" constraint="" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel/>
<y:MethodLabel/>
</y:UML>
</y:UMLClassNode>
</data>
</node>
<node id="n5">
<data key="d4"/>
<data key="d5"><![CDATA[UMLClass]]></data>
<data key="d6">
<y:UMLClassNode>
<y:Geometry height="28.0" width="100.0" x="460.0" y="346.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="19.12646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="45.58984375" x="27.205078125" y="3.0">ipcore</y:NodeLabel>
<y:UML clipContent="true" constraint="" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel/>
<y:MethodLabel/>
</y:UML>
</y:UMLClassNode>
</data>
</node>
<node id="n6">
<data key="d4"/>
<data key="d5"><![CDATA[UMLClass]]></data>
<data key="d6">
<y:UMLClassNode>
<y:Geometry height="28.0" width="100.0" x="60.0" y="406.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="19.12646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.8466796875" x="20.07666015625" y="3.0">protocol</y:NodeLabel>
<y:UML clipContent="true" constraint="" omitDetails="false" stereotype="" use3DEffect="true">
<y:AttributeLabel/>
<y:MethodLabel/>
</y:UML>
</y:UMLClassNode>
</data>
</node>
<edge id="e0" source="n1" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_delta"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="2.0" y="-40.477783203125"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n5" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_delta"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="-21.05133322010869" y="-57.01806640625"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n3" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_delta"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="76.11767578125" y="-51.59305743781886"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n4" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_delta"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="28.365337949810623" y="-87.005615234375"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n6" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_delta"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="143.96923828125" y="-81.84090935202204"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n6" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_diamond"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="32.99259440104166" y="-92.977783203125"/>
<y:BendStyle smoothed="true"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n3" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_diamond"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.962890625" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="9.783203125" x="-23.649720052083325" y="-69.95556640625">*</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e7" source="n4" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_diamond"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="-86.977783203125" y="-92.977783203125"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e8" source="n5" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="white_diamond"/>
<y:EdgeLabel alignment="center" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="six_pos" modelPosition="tail" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="-136.183349609375" y="-58.08334073153412"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources/>
</data>
</graphml>
/nocmodel/trunk/MANIFEST
0,0 → 1,33
CHANGELOG.txt
LICENSE.txt
README.txt
TODO.txt
setup.py
doc/nocmodel.basicmodels.basic_channel.html
doc/nocmodel.basicmodels.basic_ipcore.html
doc/nocmodel.basicmodels.basic_protocol.html
doc/nocmodel.basicmodels.basic_router.html
doc/nocmodel.basicmodels.html
doc/nocmodel.html
doc/nocmodel.noc_base.html
doc/nocmodel.noc_guilib.html
doc/nocmodel.noc_tlm_base.html
doc/nocmodel.noc_tlm_utils.html
examples/basic_example.py
examples/stress_test.py
nocmodel/__init__.py
nocmodel/noc_base.py
nocmodel/noc_codegen_base.py
nocmodel/noc_codegen_vhdl.py
nocmodel/noc_guilib.py
nocmodel/noc_helpers.py
nocmodel/noc_rtl_myhdl.py
nocmodel/noc_tbm_base.py
nocmodel/noc_tbm_utils.py
nocmodel/basicmodels/__init__.py
nocmodel/basicmodels/basic_channel.py
nocmodel/basicmodels/basic_ipcore.py
nocmodel/basicmodels/basic_noc_codegen.py
nocmodel/basicmodels/basic_protocol.py
nocmodel/basicmodels/basic_router.py
nocmodel/basicmodels/intercon_model.py
/nocmodel/trunk/setup.py
5,8 → 5,8
# NoCmodel - setup file
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 03-03-2011
# Version: 0.2
# Date: 05-07-2011
 
#
# This code is free software; you can redistribute it and/or
29,6 → 29,7
# Changelog:
#
# 03-03-2011 : (OD) initial release
# 05-07-2011 : (OD) second release
#
 
from distutils.core import setup
/nocmodel/trunk/README.txt
1,4 → 1,4
NoCmodel 0.1
NoCmodel 0.2
============
 
What is NoCmodel?
17,7 → 17,7
 
* Python (version 2.6 or later)
* NetworkX (version 1.4 or later) [http://networkx.lanl.gov]
* MyHDL (version 0.6 or later) [http://www.myhdl.org]
* MyHDL (version 0.7 or later) [http://www.myhdl.org]
 
Installation
------------
44,4 → 44,4
 
* Oscar Diaz <dargor@opencores.org>
 
Last update: Thu, 03 Mar 2011 18:00:20 +0100
Last update: Thu, 05 Jul 2012 22:18:47 +0200
/nocmodel/trunk/examples/basic_example.py
37,7 → 37,7
from nocmodel import *
from nocmodel.basicmodels import *
 
# Basic example model with TLM simulation
# Basic example model with TBM simulation
 
# 1. Create the model
 
61,52 → 61,52
r.update_ports_info()
r.update_routes_info()
 
# 2. add tlm support, and configure logging
add_tlm_basic_support(basicnoc, log_file="simulation.log", log_level=logging.DEBUG)
# 2. add tbm support, and configure logging
add_tbm_basic_support(basicnoc, log_file="simulation.log", log_level=logging.DEBUG)
 
# 3. Declare generators to put in the TLM simulation
# 3. Declare generators to put in the TBM simulation
 
# set ip_cores functionality as myhdl generators
def sourcegen(din, dout, tlm_ref, mydest, data=None, startdelay=100, period=100):
def sourcegen(din, dout, tbm_ref, mydest, data=None, startdelay=100, period=100):
# this generator only drives dout
@myhdl.instance
def putnewdata():
datacount = 0
protocol_ref = tlm_ref.ipcore_ref.get_protocol_ref()
mysrc = tlm_ref.ipcore_ref.router_ref.address
tlm_ref.debug("sourcegen: init dout is %s" % repr(dout.val))
protocol_ref = tbm_ref.ipcore_ref.get_protocol_ref()
mysrc = tbm_ref.ipcore_ref.router_ref.address
tbm_ref.debug("sourcegen: init dout is %s" % repr(dout.val))
yield myhdl.delay(startdelay)
while True:
if len(data) == datacount:
tlm_ref.debug("sourcegen: end of data. waiting for %d steps" % (period*10))
tbm_ref.debug("sourcegen: end of data. waiting for %d steps" % (period*10))
yield myhdl.delay(period*10)
raise myhdl.StopSimulation("data ended at time %d" % myhdl.now())
dout.next = protocol_ref.newpacket(False, mysrc, mydest, data[datacount])
tlm_ref.debug("sourcegen: data next element %d dout is %s datacount is %d" % (data[datacount], repr(dout.val), datacount))
tbm_ref.debug("sourcegen: data next element %d dout is %s datacount is %d" % (data[datacount], repr(dout.val), datacount))
yield myhdl.delay(period)
datacount += 1
return putnewdata
def checkgen(din, dout, tlm_ref, mysrc, data=None):
def checkgen(din, dout, tbm_ref, mysrc, data=None):
# this generator only respond to din
@myhdl.instance
def checkdata():
datacount = 0
protocol_ref = tlm_ref.ipcore_ref.get_protocol_ref()
mydest = tlm_ref.ipcore_ref.router_ref.address
protocol_ref = tbm_ref.ipcore_ref.get_protocol_ref()
mydest = tbm_ref.ipcore_ref.router_ref.address
while True:
yield din
if len(data) > datacount:
checkdata = din.val["data"]
tlm_ref.debug("checkgen: assert checkdata != data[datacount] => %d != %d [%d]" % (checkdata, data[datacount], datacount))
tbm_ref.debug("checkgen: assert checkdata != data[datacount] => %d != %d [%d]" % (checkdata, data[datacount], datacount))
if checkdata != data[datacount]:
tlm_ref.error("checkgen: value != %d (%d)" % (data[datacount], checkdata))
tlm_ref.debug("checkgen: assert source address != mysrc => %d != %d " % (din.val["src"], mysrc))
tbm_ref.error("checkgen: value != %d (%d)" % (data[datacount], checkdata))
tbm_ref.debug("checkgen: assert source address != mysrc => %d != %d " % (din.val["src"], mysrc))
if din.val["src"] != mysrc:
tlm_ref.error("checkgen: source address != %d (%d)" % (mysrc, din.val["src"]))
tlm_ref.debug("checkgen: assert destination address != mydest => %d != %d " % (din.val["dst"], mydest))
tbm_ref.error("checkgen: source address != %d (%d)" % (mysrc, din.val["src"]))
tbm_ref.debug("checkgen: assert destination address != mydest => %d != %d " % (din.val["dst"], mydest))
if din.val["dst"] != mydest:
tlm_ref.error("checkgen: destination address != %d (%d)" % (mydest, din.val["dst"]))
tbm_ref.error("checkgen: destination address != %d (%d)" % (mydest, din.val["dst"]))
datacount += 1
return checkdata
 
114,17 → 114,17
R11_testdata = [5, 12, 50, -11, 6, 9, 0, 3, 25]
R12_testdata = [x*5 for x in R11_testdata]
 
# 5. assign generators to ip cores (in TLM model !)
# 5. assign generators to ip cores (in TBM model !)
# R11 will send to R22, R12 will send to R21
R11.ipcore_ref.tlm.register_generator(sourcegen, mydest=R22.address, data=R11_testdata, startdelay=10, period=20)
R12.ipcore_ref.tlm.register_generator(sourcegen, mydest=R21.address, data=R12_testdata, startdelay=15, period=25)
R21.ipcore_ref.tlm.register_generator(checkgen, mysrc=R12.address, data=R12_testdata)
R22.ipcore_ref.tlm.register_generator(checkgen, mysrc=R11.address, data=R11_testdata)
R11.ipcore_ref.tbm.register_generator(sourcegen, mydest=R22.address, data=R11_testdata, startdelay=10, period=20)
R12.ipcore_ref.tbm.register_generator(sourcegen, mydest=R21.address, data=R12_testdata, startdelay=15, period=25)
R21.ipcore_ref.tbm.register_generator(checkgen, mysrc=R12.address, data=R12_testdata)
R22.ipcore_ref.tbm.register_generator(checkgen, mysrc=R11.address, data=R11_testdata)
# 6. configure simulation and run!
basicnoc.tlmsim.configure_simulation(max_time=1000)
basicnoc.tbmsim.configure_simulation(max_time=1000)
print "Starting simulation..."
basicnoc.tlmsim.run()
basicnoc.tbmsim.run()
print "Simulation finished. Pick the results in log files."
 
# 7. View graphical representation
/nocmodel/trunk/examples/stress_test.py
0,0 → 1,205
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#
# NoCmodel stress test
#
# Author: Oscar Diaz
# Version: 0.1
# Date: 20-05-2011
 
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
 
#
# Changelog:
#
# 20-05-2011 : (OD) initial release
#
 
import myhdl
import logging
import random
import time
import os
 
from nocmodel import *
from nocmodel.basicmodels import *
 
# Stress test: generate a list of random sends and receives through all the NoC.
 
sim_starttime = 10
sim_maxtime = 1000
sim_sendtime = 900
sim_meanperiod = 30 # fifo full using 13
sim_stddevperiod = 3
 
# 1. Create the model
 
basicnoc = generate_squarenoc(3, with_ipcore=True)
 
basicnoc.protocol_ref = basic_protocol()
 
basicnoc.update_nocdata()
 
# 2. add tlm support, and configure logging
add_tbm_basic_support(basicnoc, log_file="simulation.log", log_level=logging.DEBUG)
# 2.1 setup byobject logging
if not os.access("/tmp/stress_test_log/", os.F_OK):
os.mkdir("/tmp/stress_test_log/")
basicnoc.tbmsim.configure_byobject_logging(basefilename="/tmp/stress_test_log/stress", log_level=logging.DEBUG)
 
# 3. Prepare random packets
def do_checkvect(basicnoc, sim_starttime, sim_sendtime, sim_meanperiod, sim_stddevperiod):
checkvect = {}
testvect = {}
for r in basicnoc.router_list():
# generate the time instants for sending, its destination and packet value
tvec = [abs(int(x + random.gauss(0, sim_stddevperiod))) + sim_starttime for x in range(0, sim_sendtime, sim_meanperiod)]
# delete possible repeated values and sort time instants
tvec = list(set(tvec))
tvec.sort()
#avail_dest = r.routingtable.keys().remove(r.get_address())
avail_dest = r.routes_info.keys()
dest = [random.choice(avail_dest) for x in tvec]
value = [random.randrange(65536) for x in tvec]
# generate a list of "test vectors": (<time>, <dest>, <value>)
r.ipcore_ref.tbm.testvect = zip(tvec, dest, value)
testvect[r.get_address()] = r.ipcore_ref.tbm.testvect
# generate a list of expected values at every router destination
# "check vectors" is: {dest : (<time from src>, <src>, <value>)}
for i, d in enumerate(dest):
if d in checkvect:
checkvect[d].append(tuple([tvec[i], r.get_address(), value[i]]))
else:
checkvect[d] = [tuple([tvec[i], r.get_address(), value[i]])]
# sort each checkvect by time
for vect in checkvect.itervalues():
vect.sort(key=lambda x: x[0])
# put checkvects in each destination router
for r in basicnoc.router_list():
r.ipcore_ref.tbm.checkvect = checkvect[r.get_address()]
with open("vectors.txt", "w") as f:
f.write("testvect = %s\n" % repr(testvect))
f.write("checkvect = %s\n" % repr(checkvect))
#return (testvect, checkvect)
try:
execfile("vectors.txt")
for r in basicnoc.router_list():
r.ipcore_ref.tbm.testvect = testvect[r.get_address()]
r.ipcore_ref.tbm.checkvect = checkvect[r.get_address()]
print "Using vectors.txt for test"
except:
do_checkvect(basicnoc, sim_starttime, sim_sendtime, sim_meanperiod, sim_stddevperiod)
print "Created new vectors for test"
 
# 3. Declare generators to put in the TBM simulation:
# double generators that runs its own test vector and checks the expected results
 
# set ip_cores functionality as myhdl generators
def sourcechkgen(din, dout, tbm_ref):
"""
This generator drives dout based on gen_data vectors
and reacts to din to check with chk_data vectors.
"""
# prepare data indexes for check vectors
check_dict = {}
for idx, val in enumerate(tbm_ref.checkvect):
check_dict[val[2]] = idx
received_idx = [False]*len(tbm_ref.checkvect)
@myhdl.instance
def datagen():
datacount = 0
protocol_ref = tbm_ref.ipcore_ref.get_protocol_ref()
mysrc = tbm_ref.ipcore_ref.get_address()
tbm_ref.debug("sourcechkgen.datagen: init dout is %s" % repr(dout.val))
gen_data = tbm_ref.testvect
for test_vector in gen_data:
# test_vector : (<time>, <dest>, <value>)
next_delay = test_vector[0] - myhdl.now()
yield myhdl.delay(next_delay)
dout.next = protocol_ref.newpacket(False, mysrc, test_vector[1], test_vector[2])
tbm_ref.debug("sourcechkgen.datagen: sent test vector <%s>, dout is %s" % (repr(test_vector), repr(dout.val)))
# wait for end of simulation
tbm_ref.debug("sourcechkgen.datagen: test vectors exhausted. Going idle.")
# TODO: check an easy way to go idle in MyHDL
#next_delay = sim_maxtime - myhdl.now()
#yield myhdl.delay(next_delay)
#raise myhdl.StopSimulation("sourcechkgen.datagen: End of simulation")
return
 
@myhdl.instance
def datacheck():
protocol_ref = tbm_ref.ipcore_ref.get_protocol_ref()
mydest = tbm_ref.ipcore_ref.get_address()
check_data = tbm_ref.checkvect
while True:
# just check for data reception
yield din
# check packet
inpacket = din.val
# search checkvect by data payload
chkidx = check_dict.get(inpacket["data"])
if chkidx is None:
tbm_ref.error("sourcechkgen.datacheck: unexpected packet : %s" % repr(inpacket))
else:
# check vectors : (<time from src>, <src>, <value>)
expected_vector = check_data[chkidx]
# received packet: report it
received_idx[chkidx] = True
# data was checked before. Inform about packet delay
tbm_ref.debug("sourcechkgen.datacheck: (delay %d) packet received : <%s>, expected src=<%s>, value=<%s> " % (myhdl.now() - expected_vector[0], repr(inpacket), repr(expected_vector[1]), repr(expected_vector[2])))
if inpacket["src"] != expected_vector[1]:
tbm_ref.error("sourcechkgen.datacheck: source address != %d (%d)" % (expected_vector[1], inpacket["src"]))
if inpacket["dst"] != mydest:
tbm_ref.error("sourcechkgen.datacheck: destination address != %d (%d)" % (mydest, inpacket["dst"]))
@myhdl.instance
def finalcheck():
while True:
yield myhdl.delay(sim_maxtime - 1)
# final check: missing packets
tbm_ref.debug("sourcechkgen.finalcheck: check for missing packets.")
if not all(received_idx):
# missing packets:
miss_count = len(received_idx) - sum(received_idx)
tbm_ref.error("sourcechkgen.finalcheck: there are %d missing packets!" % miss_count)
for idx, val in enumerate(tbm_ref.checkvect):
if not received_idx[idx]:
tbm_ref.debug("sourcechkgen.finalcheck: missing packet: <%s>" % repr(val))
return (datagen, datacheck, finalcheck)
 
# 5. assign generators to ip cores (in TLM model !)
for r in basicnoc.router_list():
r.ipcore_ref.tbm.register_generator(sourcechkgen)
# 6. configure simulation and run!
basicnoc.tbmsim.configure_simulation(max_time=sim_maxtime)
print "Starting simulation..."
runsecs = time.clock()
basicnoc.tbmsim.run()
runsecs = time.clock() - runsecs
print "Simulation finished in %f secs. Pick the results in log files." % runsecs
 
# 7. View graphical representation
 
draw_noc(basicnoc)

powered by: WebSVN 2.1.0

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