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
No related branches found
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