Skip to content
Snippets Groups Projects
Commit 63d448b7 authored by Daniel van der Schuur's avatar Daniel van der Schuur
Browse files

-SVN copied component_class.py from the prestudy dir to here.

parent 245adf2d
Branches
No related tags found
No related merge requests found
import multiprocessing as mp
import time
import common as cm
###############################################################################
# Base classes
###############################################################################
class Signal(object):
def __init__(self, name, stype):
self.name = name
self.stype = stype
self.vhdl_signal_declaration = 'SIGNAL %s : %s;\n' %(name, stype)
class StreamPort(object):
def __init__(self, component_name, name, mode, stream_index, data_width):
self.component_name = component_name
if stream_index != None:
self.name = name + '[' + str(stream_index) + ']'
else:
self.name = name
self.mode = mode
self.stream_index = stream_index
self.data_width = data_width
self.pipe_end = None
self.port_type = 't_dp_sosi'
self.signal = Signal(component_name+'_'+name, self.port_type)
#'>' operator: Connect
def __gt__(self, other):
return self.__connect__(other)
def __connect__(self, other):
if not(self.pipe_end == None):
# The pipe end is already assigned, this is the case for composite components that
# have wired their entity port to internal instance ports.
# If self is a source port (mode='out'), this means that self.pipe_end is already occupied
# with a pipe sink end from which this entity port receives from an internal source entity.
# To make a connection between other and self, all we need to do is move the existing pipe's snk end
# from self to other. The source end remains connected to self's internal instance.
other.pipe_end = self.pipe_end
elif not(other.pipe_end == None):
# The pipe end is already assigned, this is the case for composite components that
# have wired their entity port to internal instance ports.
# If other is a sink port (mode='in'), this means that other.pipe_end is already occupied
# with a pipe source end from which this entity port send to an internal sink entity.
# To make a connection between other and self, all we need to do is move the existing pipe's src end
# from other to self. The sink end remains connected to other's internal instance.
self.pipe_end = other.pipe_end
else:
snk_end, src_end = mp.Pipe(duplex=False)
self.pipe_end = src_end
other.pipe_end = snk_end
return Connection( (self.component_name, self.name), (other.component_name, other.name) )
def send(self, item):
self.pipe_end.send(item)
def recv(self):
while True:
try:
yield self.pipe_end.recv()
except EOFError:
break
class StreamPortArray(list):
def __init__(self, component_name, name, mode, nof_streams, data_width):
list.__init__(self)
self.component_name = component_name
self.name = name
self.mode = mode
self.nof_streams = nof_streams
self.data_width = data_width
for stream_index in range(nof_streams):
self.append(StreamPort(component_name, name, mode, stream_index, data_width))
self.port_type = 't_dp_sosi_arr(%s-1 DOWNTO 0)' %nof_streams
self.signal = Signal(component_name+'_'+name, self.port_type)
#'>' operator: Connect
def __gt__(self, other):
return self.__connect__(other)
def __connect__(self, other):
for stream_port_self, stream_port_other in zip(self,other):
stream_port_self.__connect__(stream_port_other)
return Connection( (self.component_name, self.name), (other.component_name, other.name) )
def recv(self):
while True:
try:
items = []
for stream_port in self:
items.append( stream_port.pipe_end.recv() )
yield items
except EOFError:
break
class Connection():
def __init__(self, src, snk):
self.src_component_name = src[0]
self.src_port_name = src[1]
self.snk_component_name = snk[0]
self.snk_port_name = snk[1]
self.vhdl_assignment_left = self.snk_component_name + '_' + self.snk_port_name
self.vhdl_assignment_right = self.src_component_name + '_' + self.src_port_name
self.vhdl_assignment_operator = '<='
self.vhdl_assignment = self.vhdl_assignment_left + ' ' + self.vhdl_assignment_operator + ' ' + self.vhdl_assignment_right + ';\n'
class Component(mp.Process):
def __init__(self, name, components=[], connections=[], inst_nr=None):
mp.Process.__init__(self)
if inst_nr != None:
self.name = name+'_'+str(inst_nr)
else:
self.name = name
self.inst_nr = inst_nr
self.file_name = self.name + '.vhd' # Overridden by component subclasses; these assign an existing file name.
self.ports = {}
self.components = components
self.connections = connections
self.temp_connections = []
def start_components(self):
if self.components == []:
# This is not a composite component but a base component, start this instance itself
self.start()
else:
# This is a composite component, start the internal instances
for component in self.components:
print 'Starting', component
component.start_components()
def terminate_components(self):
if self.components == []:
# This is not a composite component but a base component, terminate this instance itself
self.terminate()
else:
# This is a composite component, terminate the internal instances
for component in self.components:
print 'Terminating', component
component.terminate_components()
def run_time(self, time_sec):
self.start_components()
time.sleep(time_sec)
self.terminate_components()
def generate(self, target_file=None):
if self.components != []:
target_file = open(self.file_name, "w")
target_file.write('ASTRON HEADER\n')
target_file.write('INCLUDED LIBRARIES\n')
target_file.write('ENTITY DECLARATION\n')
target_file.write('ARCHITECTURE str OF %s IS\n' %self.name)
target_file.write('. CONSTANT DECLARATIONS\n')
# Get the signal declaration from each internal component's port object
for component in self.components:
for port_name, port in component.ports.iteritems():
target_file.write(port.signal.vhdl_signal_declaration)
target_file.write('BEGIN\n')
# Write this component's connections
for connection in cm.flatten(self.connections):
# print connection
target_file.write(connection.vhdl_assignment)
# Iterate through internal components
for component in self.components:
component.generate()
target_file.write(component.get_vhdl_instance())
target_file.write('END str\n')
target_file.close()
def get_vhdl_instance(self):
# Only base components have a pre-declared VHDL instance. Composites do not.
if hasattr(self, 'vhdl_instance'):
# I'm a base component...return my pre-declared VHDL instace string
return self.vhdl_instance
else:
# I'm a composite component. Create a VHDL instance here.
return 'A string that contains the %s VHDL instance\n' %self.name
def __set_port__(self, name, mode, dimensions):
"""
Mode:
. 'in'
. 'out'
Dimension examples:
. 32 = 1 stream, 32b (sosi)
. (2,32) = 2 streams, 32b each (sosi_arr)
. (2,4,32) = 2 buses, 4 streams/bus, 32b/stream (sosi_2arr)
. (8,2,4,32) = 8 buses, 2 sub-buses/bus, 4 streams/sub-bus, 32b/stream (sosi_3arr)
"""
def __set_port__(self, name, mode, dimensions):
if isinstance(dimensions, int):
# Single stream
self.ports[name] = StreamPort(self.name, name, mode, stream_index=None, data_width=dimensions)
elif len(dimensions)==2:
# Multi stream
self.ports[name] = StreamPortArray(self.name, name, mode, nof_streams=dimensions[0], data_width=dimensions[1])
elif len(dimensions)==3:
pass
# Multi bus, multi stream
# self.ports[name] = StreamPort2Array(self.name, name, mode, nof_buses=dimensions[0], nof_streams=dimensions[1], data_width=dimensions[2])
def set_input(self, name, dimensions):
self.__set_port__(name=name, mode='in', dimensions=dimensions)
def set_output(self, name, dimensions):
self.__set_port__(name=name, mode='out', dimensions=dimensions)
#'>' operator: Connect
def __gt__(self, other):
return self.__connect__(other)
def __connect__(self, other):
for port_name_self, port_self in self.ports.iteritems():
if port_self.mode == 'out':
for port_name_other,port_other in other.ports.iteritems():
if port_other.mode == 'in':
if type(port_self)==type(port_other):
# We want to be able to daisy chain components so we need to store intermediate results
# in the component on the right.
connection = port_self.__connect__(port_other)
other.temp_connections.append(connection)
result = self.temp_connections+[connection]
self.temp_connections = []
return result
###############################################################################
# Component subclasses
###############################################################################
class SingleCounter(Component):
def __init__(self, data_width=32, inst_nr=None):
Component.__init__(self, inst_nr=inst_nr, name='SingleCounter')
self.vhdl_instance = 'A string that contains the SingleCounter VHDL instance\n'
self.set_output('src_out', data_width)
def run(self):
for value in xrange(10):
if self.inst_nr==None:
cnt_offset=0
else:
cnt_offset = self.inst_nr * 100
item = value + cnt_offset
print '[Counter] src', self.inst_nr, ': sending', item
# Offset sent value by 100 for each instance number increment
self.ports['src_out'].send(item)
class SinglePrinter(Component):
def __init__(self, data_width=32, inst_nr=None):
Component.__init__(self, inst_nr=inst_nr, name='SinglePrinter')
self.vhdl_instance = 'A string that contains the SinglePrinter VHDL instance\n'
self.set_input('snk_in', data_width)
def run(self):
for item in self.ports['snk_in'].recv():
print '[Printer] snk', self.inst_nr, ': receiving', item
class Counter(Component):
def __init__(self, nof_streams, data_width=32, inst_nr=None):
Component.__init__(self, inst_nr=inst_nr, name='Counter')
self.vhdl_instance = 'A string that contains the Counter VHDL instance\n'
self.set_output('src_out_arr', (nof_streams, data_width))
def run(self):
for value in xrange(10):
for src in self.ports['src_out_arr']:
item = value + src.stream_index*100
print '[Counter] src', src.stream_index, ': sending', item
# Offset sent value by 100 for each incremental stream
src.send(item)
class Through(Component):
def __init__(self, nof_streams, data_width=32, inst_nr=None):
Component.__init__(self, inst_nr=inst_nr, name='Through')
self.vhdl_instance = 'A string that contains the Through VHDL instance\n'
self.set_input('snk_in_arr', (nof_streams, data_width))
self.set_output('src_out_arr', (nof_streams, data_width))
def run(self):
for items in self.ports['snk_in_arr'].recv():
for item,src in zip(items, self.ports['src_out_arr']):
print '[Through] snk', src.stream_index, ': forwarding', item, 'to src', src.stream_index
src.send(item)
class Printer(Component):
def __init__(self, nof_streams, data_width=32, inst_nr=None):
Component.__init__(self, inst_nr=inst_nr, name='Printer')
self.vhdl_instance = 'A string that contains the Printer VHDL instance\n'
self.set_input('snk_in_arr', (nof_streams, data_width))
def run(self):
for items in self.ports['snk_in_arr'].recv():
for item_index, item in enumerate(items):
print '[Printer] snk', item_index, ': receiving', item
###############################################################################
# Help function for keypress
###############################################################################
def press_enter():
try:
input("Press enter to continue")
except SyntaxError:
pass
###############################################################################
# Main
###############################################################################
print
print '###############################################################################'
print '# Example 1: connect ports component-wise'
print '###############################################################################'
print
nof_streams = 3
a = Counter(nof_streams)
b = Through(nof_streams)
c = Printer(nof_streams)
connections = [ a>b>c ]
d = Component('my_component_1', [a,b,c], connections)
d.run_time(1)
d.generate()
press_enter()
print
print '###############################################################################'
print '# Example 2: connect ports array-wise'
print '###############################################################################'
print
nof_streams = 3
a = Counter(nof_streams)
b = Through(nof_streams)
c = Printer(nof_streams)
connections = []
connections.append( a.ports['src_out_arr'] > b.ports['snk_in_arr' ] )
connections.append( b.ports['src_out_arr'] > c.ports['snk_in_arr'] )
d = Component('my_component_2', [a,b,c], connections)
d.run_time(1)
d.generate()
press_enter()
print
print '###############################################################################'
print '# Example 3: connect ports stream-wise (with stream 0 / stream 1 swap)'
print '###############################################################################'
print
nof_streams = 3
a = Counter(nof_streams)
b = Through(nof_streams)
c = Printer(nof_streams)
connections = []
connections.append( a.ports['src_out_arr'][0] > b.ports['snk_in_arr' ][0] )
connections.append( a.ports['src_out_arr'][1] > b.ports['snk_in_arr' ][1] )
connections.append( a.ports['src_out_arr'][2] > b.ports['snk_in_arr' ][2] )
connections.append( b.ports['src_out_arr'][1] > c.ports['snk_in_arr'][0] ) # We're swapping streams 0 and 1 here
connections.append( b.ports['src_out_arr'][0] > c.ports['snk_in_arr'][1] ) # We're swapping streams 0 and 1 here
connections.append( b.ports['src_out_arr'][2] > c.ports['snk_in_arr'][2] )
d = Component('my_component_3', [a,b,c], connections)
d.run_time(1)
d.generate()
press_enter()
print
print '###############################################################################'
print '# Example 4: Mix single and multi stream components'
print '###############################################################################'
print
nof_streams = 1
a = SingleCounter()
b = Through(nof_streams)
c = Printer(nof_streams)
connections = []
connections.append( a.ports['src_out'] > b.ports['snk_in_arr' ][0] )
connections.append( b.ports['src_out_arr'] > c.ports['snk_in_arr'] )
d = Component('my_component_4', [a,b,c], connections)
d.run_time(1)
d.generate()
press_enter()
print
print '###############################################################################'
print '# Example 5: Creating multi-instance composites from single stream components'
print '# . We replace the Counter with a new component that instantiates 3 SingeCounters'
print '# . We replace the Printer with a new component that instantiates 3 SingePrinters'
print '###############################################################################'
print
nof_streams = 3
data_width = 32
# Create [nof_streams] SingleCounter instances
a_list = []
for i in range(nof_streams):
a_list.append(SingleCounter(inst_nr=i))
# Create a new components wrapping these SingleCounter instances
a_multi = Component('a_multi', a_list)
# Declare the output of this new component
a_multi.set_output('src_out_arr', (nof_streams, data_width))
# Forward the SingleCounter outputs to the new component's output
for i in range(nof_streams):
a_multi.components[i].ports['src_out'] > a_multi.ports['src_out_arr'][i]
# Unchanged: the Through component
b = Through(nof_streams)
# Create [nof_streams] SinglePrinter instances
c_list = []
for i in range(nof_streams):
c_list.append(SinglePrinter(inst_nr=i))
# Create a new components wrapping these SinglePrinter instances
c_multi = Component('c_multi', c_list)
# Declare the input of this new component
c_multi.set_input('snk_in_arr', (nof_streams, data_width))
# Forward the new component's input to the SinglePrinter inputs
for i in range(nof_streams):
c_multi.ports['snk_in_arr'][i] > c_multi.components[i].ports['snk_in']
# Continue as before (in the other examples)
connections = [ a_multi>b>c_multi ]
d = Component('my_component_5', [a_multi,b,c_multi], connections)
d.run_time(1)
d.generate()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment