From Python to silicon
from myhdl import *
# George Pantazopoulos
# 10 Oct 2006
# Key concepts:
# Hardware Module: aka "module". Different meaning than a Python module.
# Signal: A connection between one or more modules.
#         A Signal may be driven by only one module at a time
# Signal Group: A connection of related signals
# Port:   A module's connection to the world outside it.
#         To connect a module, connect signals to its ports
# Port Group: A collection of related ports
# TODO: Break out ASCII Port Spec parser into own class
class Port(object):
	def __init__(self,name, direction, descr=""): 	= name
	    self.signal = None
	    directions = ['in', 'out', 'inout']
	    if direction not in directions:
		   raise Exception, \
		   "Direction needs to be one of " + str(directions)
	    self.dir 	= direction
	    self.descr 	= descr
	def connect_to(self, signal):
	    signal should be of type <class 'myhdl_.Signal.Signal'>
	    self.signal = signal
	def get_name(self):
	def get_descr(self):
		return self.descr
	def sig(self):
	    # It's helpful to error here if the 'signal'
	    # is not set. Otherwise the errors in MyHDL are confusing
	    # TODO: is this the right place for this?
	    # Maybe if we just return the None value it can cause an
	    # exception elsewhere
	    if self.signal == None:
		   raise Exception, \
		   "port '" + str( + "' has no signal connected to it"
	    return self.signal
# generic record-keeping class
class rec:
	def __getattr__(self, attrname):
		return self.__dict__[attrname]
	def __setattr__(self, attr, value):
		self.__dict__[attr] = value	
	def __repr__(self):
		s = ""
		for key in self.__dict__:
			s += key + ": " + repr(self.__dict__[key])
			s += '\n'
		return s
class HardwareModule:
	def __init__(self):
		# A collection of port groups
		self.__dict__['port_groups'] = rec()
	def __getattr__(self, attrname):
		if attrname == 'ports':
			return self.__dict__['port_groups']
			raise AttributeError, attrname
	def __setattr__(self, attr, value):
		if attr == 'ports':
			self.__dict__[attr] = value
			self.__dict__[attr] = value
	def add_port_group(self, name):
		Add an empty port group
		self.port_groups.__setattr__(name, rec())
	def connect(self, port, sig):
		Connect a port in the design to an external signal
		Must qualify port name within a port group with a '.'
		clk = Signal(bool(0))
		uc = UpCounter()
		uc.connect('wishbone.clk_i', clk)
		# The port name will be qualified with the port group
		fqpn = port.split('.')
	def parse_portspec(self, s):
	    Automatically parses an Ascii Port Specification
	    and generates port groups that contain the correct ports.
	    Example portspec:
	    Begin portspec
	    Name    Dir   Width         Group           Descr         
	    clk_i   in    1             wishbone        clock   input
	    rst_i   in    1             wishbone        reset   input
	    count_o out   count_width   non_wishbone    counter output
	    End portspec
	    In the port attribute line there must be at least one char whitespace
	    between port attributes. Currently only spaces are supported, not tabs.
	    __version__ = "0.2.0"
	    beginstr = "Begin portspec"
	    endstr   = "End portspec"
	    # It's a assumed that a docstring will be inputted.
	    # Break up the string into seperate lines
	    lines = s.splitlines()
	    def find_in_str_list(str_list, substr):
		   Given a list of strings, return the list index
		   of the string containing the first occurence
		   of substr.
		   If not found, returns -1
		   index = -1
		   # For each string in the list
		   for i in range(len(str_list)):
			  # look for substr
			  hindex = str_list[i].find(substr)
			  # if found, break.
			  # We dont care about the horizontal position of the substring
			  if hindex != -1:
				 index = i
		   return index
	    # Search for the begin string
	    beginstr_line = find_in_str_list(lines, beginstr)
	    # If no begin string found, then error
	    if beginstr_line == -1:
		   raise Exception, \
		   "port specification must begin with: " + beginstr + "on its own line"
	    # Search for the end string
	    endstr_line   = find_in_str_list(lines, endstr)
	    # If no begin string found, then error
	    if endstr_line == -1:
		   raise Exception, \
		   "port specification must end with: " + endstr + "on its own line"
	    min_num_lines = 4
	    if endstr_line - beginstr_line < min_num_lines:
		   raise Exception, "\n" + \
		  "There must be at least " + str(min_num_lines) + \
		  "lines between the begin and end strings"		    
	    # ignore the next line
	    # The following line should contain the port attribute types
	    # Name,Dir, Width, Class, Descr
	    pat_str_line = beginstr_line + 2
	    pat_str = lines[pat_str_line]    
	    pats = dict(		 _name  = 'Name',
						  _dir   = 'Dir',
						  _width = 'Width',
						  _group = 'Group',
						  _descr = 'Descr')
	    pat_indices =    dict( _name  = -1,
						  _dir   = -1,
						  _width = -1,
						  _group = -1,
						  _descr = -1)
	    # Find all of these and record their horizonal indices
	    for pat in pats:
		   ps = pats[pat]
		   idx = pat_str.find(ps)
		   # If even one of them is not found, it's an error
		   if idx == -1:
			  raise Exception, \
			  "Could not find " + ps + " in Port Attribute Types line"
		   # Record its horizontal index
		   pat_indices[pat] = idx
	    import pprint
	    # Enforce a particular order for the port attribute types
	    pat_order = \
	    [pats['_name'], pats['_dir'], pats['_width'], pats['_group'], pats['_descr']]
	    # Split the given port attribute string into a list of seperate strings
	    # and compare the it against the reference order list
	    if pat_str.split() != pat_order:
		   # Build an example string to show the user
		   example_str = ""
		   for s in pat_order:
			  example_str += s
			  example_str += " "
		   # Note, this exception may also be raised if an extra column was added
		   raise Exception, \
		   "\nInvalid port attribute types line: (line #" + \
		   str(pat_str_line) + " of docstring)\n" +\
		   "'" + pat_str + "'" + \
		   "\nOnly these port attribute types must be present " + \
		   "and be in the following order:\n" + \
		   "'" + example_str + "'"
	    # ignore the next line
	    first_port_attr_line = pat_str_line + 2
	    last_port_attr_line  = endstr_line - 1
	    pa_dicts = dict()
	    for line in lines[first_port_attr_line:last_port_attr_line]:
		   # Skip this line if it consists entirely of whitespace
		   if len(line.split()) <= 0:
		   # Each port attribute is supposed to be lined up horizontally
		   # with each port attribute type up top.
		   # For each user port attribute type, grab
		   # the user port attribute string that is lined up beneath it
		   pa_dict = dict()
		   for pat in pat_indices:
			  pat_index = pat_indices[pat]
			  # from the user port attribute line, extract a substring
			  # starting at the column of the port attribute type above it
			  # and going to the end of the line
			  pa_plus_rest_of_line = line[pat_index-1:]
			  # Split this portion into tokens and take the first one
			  pa = pa_plus_rest_of_line.split()[0]
			  # For each port attribute line
			  # Create a dictionary containing all the user-supplied
			  # port attributes
			  # eg. foo = dict('_name'='clk_i', '_dir'='inout')
			  pa_dict[pat] = pa
		   # To associate all the port attributes with a port name
		   # stuff that dictionary inside another dictionary with the
		   # key being the port's given name.
		   # eg
		   # bar = dict(foo['name']=foo)
		   port_name = pa_dict['_name']
	    # For each port attribute 'group' found, create a port group
	    # They are attributes of a simple record-keeping class
	    port_groups = rec()
	    for port_name in pa_dicts:
		   port_groupname = pa_dicts[port_name]['_group']
		   port_groups.__setattr__(port_groupname, rec())
	    # Now that we have our port groups, put each port in the correct
	    # port group
	    for port_name in pa_dicts:
		   port_dir			= pa_dicts[port_name]['_dir']
		   port_groupname 	= pa_dicts[port_name]['_group']
		   port_descr		= pa_dicts[port_name]['_descr']
		   # Create a port
		   # TODO: support more attributes or use dict directly
		   p = Port(name=port_name, direction=port_dir, descr=port_descr)
		   # Add it to the correct port group
		   port_groups.__getattr__(port_groupname).__setattr__(port_name, p)
	    return port_groups
class UpCounter(HardwareModule):
	Begin portspec
	Name    Dir   Width         Group           Descr         
	clk_i   in    1             wishbone        clock   input
	rst_i   in    1             wishbone        reset   input
	count_o out   count_width   non_wishbone    counter output
	End portspec
	# TODO: Have portspec parser handle tabs
	# TODO: Also, spaces and tabs should be allowed for Descr
	def __init__(self):
		# Need to initialize superclass
		# Auto-generated ports and port groups! 
		# TODO: make error messages more friendly
		# (eg. "Could not parse port spec")
		self.ports = self.parse_portspec(self.__doc__)
	def up_counter(self, clk_i, rst_i, count_o):
		up-counter MyHDL implementation
		def proc():
		  if rst_i: = 0
		  else: = count_o + 1
		return instances()	
	def hw_inst(self):
		Connects the ports of the implementation to the Signals
		in each class-level port and returns the connected unit.
		return self.up_counter(clk_i   = self.ports.wishbone.clk_i.sig(), 
							   rst_i   = self.ports.wishbone.rst_i.sig(), 
							   count_o = self.ports.non_wishbone.count_o.sig())
def top(clk, rst):
	count = Signal(intbv(0)[3:])
	uc = UpCounter()
	uc.connect('wishbone.clk_i', clk)
	uc.connect('wishbone.rst_i', rst)
	uc.connect('non_wishbone.count_o', count)
	UC_INST = uc.hw_inst()
	return instances()
clk = Signal(bool(0))
rst = Signal(bool(0))
toVerilog(top, clk, rst)
users/george_pantazopoulos/demo_1.txt · Last modified: 2006/10/10 12:02 by themaxx
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki