Ejemplo n.º 1
0
	def test_fully_connect_chips_pair_of_chips_no_wrap_around(self):
		"""
		Test that a model.fully_connect_chips connects (and leaves disconnected)
		the correct links when a pair of touching chips are created.
		"""
		# Test with the neighbouring chip being on every possible edge.
		for direction in [ topology.EAST
		                 , topology.NORTH_EAST
		                 , topology.NORTH
		                 , topology.WEST
		                 , topology.SOUTH_WEST
		                 , topology.SOUTH
		                 ]:
			other_chip_position = topology.to_xy(topology.add_direction((0,0,0), direction))
			chips = { (0,0)               : model.make_chip((0,0))
			        , other_chip_position : model.make_chip(other_chip_position)
			        }
			model.fully_connect_chips(chips)
			
			# Only the touching ports are connected
			for port in model.Router.EXTERNAL_PORTS:
				if port == direction:
					# Touching port
					self.assertEqual( chips[(0,0)].router.connections[port]
					                , chips[other_chip_position].router
					                )
					self.assertEqual( chips[other_chip_position].router.connections[topology.opposite(port)]
					                , chips[(0,0)].router
					                )
				else:
					# Non-touching port
					self.assertIsNone(chips[(0,0)].router.connections[port])
					self.assertIsNone(chips[other_chip_position].router.connections[topology.opposite(port)])
Ejemplo n.º 2
0
	def follow_packet(self, in_wire_side, packet_direction):
		"""
		Follow the path of a packet which entered in to the board via the wire
		in_wire_side following packet_direction through the chips in the board.
		Returns a tuple (next_in_wire_side, next_board).
		
		We only need to know the side on which the incoming link is on (not the
		exact chip) because for any incoming side there is a fixed outgoing side
		when travelling in a fixed direction.
		"""
		
		# Mapping of {(in_wire_side, packet_direction) : out_wire_side,...}
		out_sides = {
			(topology.SOUTH_WEST, topology.EAST)       : topology.EAST,
			(topology.WEST,       topology.EAST)       : topology.NORTH_EAST,
			
			(topology.SOUTH_WEST, topology.NORTH_EAST) : topology.NORTH,
			(topology.SOUTH,      topology.NORTH_EAST) : topology.NORTH_EAST,
			
			(topology.SOUTH,      topology.NORTH)      : topology.WEST,
			(topology.EAST,       topology.NORTH)      : topology.NORTH,
		}
		# Opposite cases are simply inverted versions of the above...
		for (iws, pd), ows in out_sides.items():
			out_sides[( topology.opposite(iws)
			          , topology.opposite(pd)
			          )] = topology.opposite(ows)
		
		out_wire_side = out_sides[(in_wire_side, packet_direction)]
		
		return (topology.opposite(out_wire_side), self.follow_wire(out_wire_side))
Ejemplo n.º 3
0
	def test_fully_connect_chips_pair_of_chips_no_wrap_around(self):
		"""
		Test that a model.fully_connect_chips connects (and leaves disconnected)
		the correct links when a pair of touching chips are created.
		"""
		# Test with the neighbouring chip being on every possible edge.
		for direction in [ topology.EAST
		                 , topology.NORTH_EAST
		                 , topology.NORTH
		                 , topology.WEST
		                 , topology.SOUTH_WEST
		                 , topology.SOUTH
		                 ]:
			other_chip_position = topology.to_xy(topology.add_direction((0,0,0), direction))
			chips = { (0,0)               : model.make_chip((0,0))
			        , other_chip_position : model.make_chip(other_chip_position)
			        }
			model.fully_connect_chips(chips)
			
			# Only the touching ports are connected
			for port in model.Router.EXTERNAL_PORTS:
				if port == direction:
					# Touching port
					self.assertEqual( chips[(0,0)][0].connections[port]
					                , chips[other_chip_position][0]
					                )
					self.assertEqual( chips[other_chip_position][0].connections[topology.opposite(port)]
					                , chips[(0,0)][0]
					                )
				else:
					# Non-touching port
					self.assertIsNone(chips[(0,0)][0].connections[port])
					self.assertIsNone(chips[other_chip_position][0].connections[topology.opposite(port)])
Ejemplo n.º 4
0
    def follow_packet(self, in_wire_side, packet_direction):
        """
		Follow the path of a packet which entered in to the board via the wire
		in_wire_side following packet_direction through the chips in the board.
		Returns a tuple (next_in_wire_side, next_board).
		
		We only need to know the side on which the incoming link is on (not the
		exact chip) because for any incoming side there is a fixed outgoing side
		when travelling in a fixed direction.
		"""

        # Mapping of {(in_wire_side, packet_direction) : out_wire_side,...}
        out_sides = {
            (topology.SOUTH_WEST, topology.EAST): topology.EAST,
            (topology.WEST, topology.EAST): topology.NORTH_EAST,
            (topology.SOUTH_WEST, topology.NORTH_EAST): topology.NORTH,
            (topology.SOUTH, topology.NORTH_EAST): topology.NORTH_EAST,
            (topology.SOUTH, topology.NORTH): topology.WEST,
            (topology.EAST, topology.NORTH): topology.NORTH,
        }
        # Opposite cases are simply inverted versions of the above...
        for (iws, pd), ows in out_sides.items():
            out_sides[(topology.opposite(iws),
                       topology.opposite(pd))] = topology.opposite(ows)

        out_wire_side = out_sides[(in_wire_side, packet_direction)]

        return (topology.opposite(out_wire_side),
                self.follow_wire(out_wire_side))
Ejemplo n.º 5
0
	def connect_wire(self, other, direction):
		"""
		Connect a wire between this board and another for the given direction.
		"""
		# Ensure it isn't already connected
		assert(self.follow_wire(direction) is None)
		assert(other.follow_wire(topology.opposite(direction)) is None)
		
		self.connection[direction] = other
		other.connection[topology.opposite(direction)] = self
Ejemplo n.º 6
0
    def connect_wire(self, other, direction):
        """
		Connect a wire between this board and another for the given direction.
		"""
        # Ensure it isn't already connected
        assert (self.follow_wire(direction) is None)
        assert (other.follow_wire(topology.opposite(direction)) is None)

        self.connection[direction] = other
        other.connection[topology.opposite(direction)] = self
Ejemplo n.º 7
0
def table_gen(router):
	"""
	Generate a routing table description file for a given router based on the
	format used for loading by ybug.
	"""
	
	# A list of (route_bits, key, mask) tuples corresponding to the router entries
	# required.
	table_entries = []
	
	# Work out what routing entries are required
	for route, (incoming_port, outgoing_ports) in router.routes.iteritems():
		# Routes which simply forward packets without changing their
		# direction/forking are default routed and do not require a table entry.
		if not ( incoming_port in model.Router.EXTERNAL_PORTS \
		         and len(outgoing_ports) == 1 \
		         and topology.opposite(incoming_port) in outgoing_ports
		       ):
			route_bits = sum(LINK_BITS[port] for port in outgoing_ports)
			key = route.key
			mask = 0xFFFFFFFF
			table_entries.append((route_bits, key, mask))
	
	# Generate the binary formatted table entries
	out = ""
	for entry_num, (route_bits, key, mask) in enumerate(table_entries):
		out += rtr_entry_t.pack(entry_num, len(table_entries), route_bits, key, mask)
	
	# Terminate with an empty all-ones entry
	out += rtr_entry_t.pack(0xFFFF, 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)
	
	return out
Ejemplo n.º 8
0
	def test_connections(self):
		# Try with several sizes
		for torus_size in SpiNNakerTorusTests.TORUS_SIZES:
			self.generate_torus(*torus_size)
			
			# Get a dictionary of chips to their locations
			chips = {}
			for board in self.torus.boards.itervalues():
				for chip in board.chips.itervalues():
					chips[chip.get_mesh_position()] = chip
			
			# Check each chip is connected with their neighbours N, NE, W
			for pos, chip in chips.iteritems():
				for direction in [topology.NORTH, topology.NORTH_EAST, topology.WEST]:
					other_pos = topology.to_xy(
						topology.add_direction(topology.zero_pad(pos), direction))
					other_chip = chips[( other_pos[0]%(self.torus.width*12)
					                   , other_pos[1]%(self.torus.height*12)
					                   , )]
					
					other_direction = topology.opposite(direction)
					
					# Make sure we share links
					self.assertEqual(chip.get_in_link(direction),
					                 other_chip.get_out_link(other_direction))
					self.assertEqual(chip.get_out_link(direction),
					                 other_chip.get_in_link(other_direction))
Ejemplo n.º 9
0
def table_gen(router):
    """
	Generate a routing table description file for a given router based on the
	format used for loading by ybug.
	"""

    # A list of (route_bits, key, mask) tuples corresponding to the router entries
    # required.
    table_entries = []

    # Work out what routing entries are required
    for route, (incoming_port, outgoing_ports) in router.routes.iteritems():
        # Routes which simply forward packets without changing their
        # direction/forking are default routed and do not require a table entry.
        if not ( incoming_port in model.Router.EXTERNAL_PORTS \
                 and len(outgoing_ports) == 1 \
                 and topology.opposite(incoming_port) in outgoing_ports
               ):
            route_bits = sum(LINK_BITS[port] for port in outgoing_ports)
            key = route.key
            mask = 0xFFFFFFFF
            table_entries.append((route_bits, key, mask))

    # Generate the binary formatted table entries
    out = ""
    for entry_num, (route_bits, key, mask) in enumerate(table_entries):
        out += rtr_entry_t.pack(entry_num, len(table_entries), route_bits, key,
                                mask)

    # Terminate with an empty all-ones entry
    out += rtr_entry_t.pack(0xFFFF, 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)

    return out
Ejemplo n.º 10
0
	def test_threeboard_packets(self):
		# Exhaustively check that packets travelling in each direction take the
		# correct number of hops to wrap back according to Simon Davidson's model.
		for testcase in BoardTests.TEST_CASES:
			w, h = testcase
			boards = board.create_torus(w, h)
			
			# Try starting from every board
			for start_board, start_coord in boards:
				# Try going in every possible direction
				for direction in [ topology.EAST
				                 , topology.NORTH_EAST
				                 , topology.NORTH
				                 , topology.WEST
				                 , topology.SOUTH_WEST
				                 , topology.SOUTH
				                 ]:
					# Packets can enter when travelling in direction from the side with the
					# opposite label and one counter-clockwise from that.
					for entry_point in [topology.opposite(direction)
					                   , topology.next_ccw(topology.opposite(direction))
					                   ]:
						num_boards = len(list(board.follow_packet_loop(start_board, entry_point, direction)))
						# For every threeboard traversed, the number of chips traversed is 3*l
						# where l is the number of rings in the hexagon. Travelling in one
						# direction we pass through a threeboard every two boards traversed so
						# the number of nodes traversed is num_nodes*l where num_hops is given
						# as below.
						num_nodes = (num_boards/2) * 3
						
						# The principal axis is south to north, i.e. along the height in
						# threeboards. This should have 3*l*h nodes along its length.
						if direction in (topology.NORTH, topology.SOUTH):
							self.assertEqual(num_nodes, h*3)
						
						# The major axis is east to west, i.e. along the width in
						# threeboards. This should have 3*l*w nodes along its length.
						if direction in (topology.EAST, topology.WEST):
							self.assertEqual(num_nodes, w*3)
						
						# The minor axis is norht-east to south-west, i.e. diagonally across
						# the mesh of threeboards. This should have 3*l*lcm(w,h) nodes along
						# its length.
						if direction in (topology.NORTH_EAST, topology.SOUTH_WEST):
							self.assertEqual(num_nodes, self.lcm(w,h)*3)
Ejemplo n.º 11
0
def wire_length(boards, board, direction, wire_offsets={}):
    """
	Returns the length of a wire leaving the specified board in a given direction.
	
	boards is a list [(board, coord),...)] where all coords support subtraction
	and magnitude() (such as those from the coordinates module).
	
	board is a board in that list
	
	direction is a wire direction to measure
	
	wire_offsets is an (optional) dict {direction:offset,...} where the offset
	supplied for each direction.
	"""
    b2c = dict(boards)
    source = b2c[board]
    target = b2c[board.connection[direction]]

    if direction in wire_offsets:
        source += wire_offsets[direction]
    if topology.opposite(direction) in wire_offsets:
        target += wire_offsets[topology.opposite(direction)]

    return (source - target).magnitude()
Ejemplo n.º 12
0
def wire_length(boards, board, direction, wire_offsets={}):
	"""
	Returns the length of a wire leaving the specified board in a given direction.
	
	boards is a list [(board, coord),...)] where all coords support subtraction
	and magnitude() (such as those from the coordinates module).
	
	board is a board in that list
	
	direction is a wire direction to measure
	
	wire_offsets is an (optional) dict {direction:offset,...} where the offset
	supplied for each direction.
	"""
	b2c = dict(boards)
	source = b2c[board]
	target = b2c[board.connection[direction]]
	
	if direction in wire_offsets:
		source += wire_offsets[direction]
	if topology.opposite(direction) in wire_offsets:
		target += wire_offsets[topology.opposite(direction)]
	
	return (source - target).magnitude()
Ejemplo n.º 13
0
def get_router_entries(router):
	"""
	Given a router, returns a list of (route_bits, key, mask) tuples.
	"""
	# A list of (route_bits, key, mask) tuples corresponding to the router entries
	# required.
	table_entries = []
	
	# Work out what routing entries are required
	for route, (incoming_port, outgoing_ports) in router.routes.iteritems():
		# Routes which simply forward packets without changing their
		# direction/forking are default routed and do not require a table entry.
		if not ( incoming_port in model.Router.EXTERNAL_PORTS \
		         and len(outgoing_ports) == 1 \
		         and topology.opposite(incoming_port) in outgoing_ports
		       ):
			route_bits = sum(LINK_BITS[port] for port in outgoing_ports)
			key = route.key
			mask = 0xFFFFFFFF
			table_entries.append((route_bits, key, mask))
	
	return table_entries
Ejemplo n.º 14
0
def fully_connect_chips(chips, wrap_around = False):
	"""
	Given a set of chips (i.e. (router, cores) tuples), fully interconnects the
	chips optionally including wrap-around links.
	"""
	# Calculate the bounds of the system's size (in case wrap_around is used)
	width  = max(x for (x,y) in chips.iterkeys()) + 1
	height = max(y for (x,y) in chips.iterkeys()) + 1
	
	# Connect up the nodes to their neighbours
	for position, (router, cores) in chips.iteritems():
		for direction in [topology.EAST, topology.NORTH_EAST, topology.NORTH]:
			next_x, next_y = topology.to_xy(
				topology.add_direction(topology.to_xyz(position), direction))
			
			if wrap_around:
				next_x %= width
				next_y %= height
			
			# Only connect up to nodes which actually exist...
			if (next_x, next_y) in chips:
				router.connect(direction, chips[(next_x, next_y)][0], topology.opposite(direction))
Ejemplo n.º 15
0
	def test_chips(self):
		# A board should have chips in the correct locations and no repeats
		self.assertEqual(len(self.board.chips), 48)
		self.assertEqual(set(self.board.chips.iterkeys()),
		                 set(topology.hexagon(4)))
		
		# For all inputs & outputs, if there is a chip in that direction it must be
		# connected via a SilistixLink and if not it should be attached to a
		# DeadLink.
		for src_pos, src_chip in self.board.chips.iteritems():
			for direction in ( topology.EAST
			                 , topology.NORTH_EAST
			                 , topology.NORTH
			                 , topology.WEST
			                 , topology.SOUTH_WEST
			                 , topology.SOUTH
			                 ):
				in_link  = src_chip.get_in_link(direction)
				out_link = src_chip.get_out_link(direction)
				
				dst_pos = topology.to_xy(topology.add_direction(topology.zero_pad(src_pos),
				                                                direction))
				if dst_pos in self.board.chips:
					# There is a chip opposite this connection
					dst_chip = self.board.chips[dst_pos]
					direction = topology.opposite(direction)
					
					# Check that they have the same link (connected to opposite ports)
					self.assertEqual(out_link, dst_chip.get_in_link(direction))
					self.assertEqual(in_link,  dst_chip.get_out_link(direction))
					
					# And that they're SilistixLinks
					self.assertEqual(type(in_link), SilistixLink)
					self.assertEqual(type(out_link), SilistixLink)
				else:
					# No adjacent chip so should be DeadLinks
					self.assertEqual(type(in_link), DeadLink)
					self.assertEqual(type(out_link), DeadLink)
Ejemplo n.º 16
0
def fully_connect_chips(chips, wrap_around=False):
    """
	Given a set of chips (i.e. (router, cores) tuples), fully interconnects the
	chips optionally including wrap-around links.
	"""
    # Calculate the bounds of the system's size (in case wrap_around is used)
    width = max(x for (x, y) in chips.iterkeys()) + 1
    height = max(y for (x, y) in chips.iterkeys()) + 1

    # Connect up the nodes to their neighbours
    for position, (router, cores) in chips.iteritems():
        for direction in [topology.EAST, topology.NORTH_EAST, topology.NORTH]:
            next_x, next_y = topology.to_xy(
                topology.add_direction(topology.to_xyz(position), direction))

            if wrap_around:
                next_x %= width
                next_y %= height

            # Only connect up to nodes which actually exist...
            if (next_x, next_y) in chips:
                router.connect(direction, chips[(next_x, next_y)][0],
                               topology.opposite(direction))
Ejemplo n.º 17
0
	def test_add_route(self):
		"""
		Test that model.add_route successfully works for a simple multicast route (and
		that defining the route twice has no ill-effects).
		"""
		chips = model.make_rectangular_board(2,2)
		
		# Make a path travelling round the system (do it twice to make sure nothing
		# gets duplicated)
		route = model.Route(0)
		for _ in range(2):
			model.add_route( route
			               , [ chips[(0,0)].cores[0]
			                 , chips[(0,0)].router
			                 , chips[(0,1)].router
			                 , chips[(1,1)].router
			                 , chips[(1,0)].router
			                 , chips[(1,0)].cores[17]
			                 ]
			               )
			model.add_route( route
			               , [ chips[(0,0)].cores[0]
			                 , chips[(0,0)].router
			                 , chips[(0,1)].router
			                 , chips[(1,1)].router
			                 , chips[(1,1)].cores[17]
			                 ]
			               )
		
		# Check that the route was added in the appropriate sink/source and nowhere
		# else
		for (position, core) in sum(( list((router.position, core) for core in cores.itervalues())
		                              for (router,cores) in chips.itervalues()
		                            ), []):
			# Source should be in chip (0,0)'s 0th core
			if position == (0,0) and core.core_id == 0:
				self.assertEqual(core.sources, set([route]))
			else:
				self.assertEqual(core.sources, set())
			
			# Sink should be in chips (1,0)'s and (1,1)'s 17th core
			if position in ((1,0), (1,1)) and core.core_id == 17:
				self.assertEqual(core.sinks, set([route]))
			else:
				self.assertEqual(core.sinks, set())
		
		
		# Check that all connecting edges between routers are valid (i.e. face in
		# opposite directions and make sense)
		for router, cores in chips.itervalues():
			for route, (input_port, output_ports) in router.routes.iteritems():
				# Test the input has a corresponding output in the router/core
				if input_port in model.Router.INTERNAL_PORTS:
					# If a route is from a core, make sure the core knows about it
					core = router.connections[input_port]
					self.assertIn(route, core.sources)
				else:
					# Check the corresponding router has an output for this route pointing
					# at this router.
					other_router = router.connections[input_port]
					self.assertIn( topology.opposite(input_port)
					             , other_router.routes[route][1]
					             )
				
				# Test all outputs have a coresponding input in another router/core
				for output_port in output_ports:
					if output_port in model.Router.INTERNAL_PORTS:
						# If a route is to a core, make sure the core knows about it
						core = router.connections[output_port]
						self.assertIn(route, core.sinks)
					else:
						# Check the corresponding router has an input for this route pointing
						# from this router.
						other_router = router.connections[output_port]
						self.assertEqual( topology.opposite(output_port)
						                , other_router.routes[route][0]
						                )
Ejemplo n.º 18
0
	def test_add_route(self):
		"""
		Test that model.add_route successfully works for a simple multicast route (and
		that defining the route twice has no ill-effects).
		"""
		chips = model.make_rectangular_board(2,2)
		
		# Make a path travelling round the system (do it twice to make sure nothing
		# gets duplicated)
		route = model.Route(0)
		for _ in range(2):
			model.add_route( route
			               , [ chips[(0,0)][1][0]
			                 , chips[(0,0)][0]
			                 , chips[(0,1)][0]
			                 , chips[(1,1)][0]
			                 , chips[(1,0)][0]
			                 , chips[(1,0)][1][17]
			                 ]
			               )
			model.add_route( route
			               , [ chips[(0,0)][1][0]
			                 , chips[(0,0)][0]
			                 , chips[(0,1)][0]
			                 , chips[(1,1)][0]
			                 , chips[(1,1)][1][17]
			                 ]
			               )
		
		# Check that the route was added in the appropriate sink/source and nowhere
		# else
		for (position, core) in sum(( list((router.position, core) for core in cores)
		                              for (router,cores) in chips.itervalues()
		                            ), []):
			# Source should be in chip (0,0)'s 0th core
			if position == (0,0) and core.core_id == 0:
				self.assertEqual(core.sources, set([route]))
			else:
				self.assertEqual(core.sources, set())
			
			# Sink should be in chips (1,0)'s and (1,1)'s 17th core
			if position in ((1,0), (1,1)) and core.core_id == 17:
				self.assertEqual(core.sinks, set([route]))
			else:
				self.assertEqual(core.sinks, set())
		
		
		# Check that all connecting edges between routers are valid (i.e. face in
		# opposite directions and make sense)
		for router, cores in chips.itervalues():
			for route, (input_port, output_ports) in router.routes.iteritems():
				# Test the input has a corresponding output in the router/core
				if input_port in model.Router.INTERNAL_PORTS:
					# If a route is from a core, make sure the core knows about it
					core = router.connections[input_port]
					self.assertIn(route, core.sources)
				else:
					# Check the corresponding router has an output for this route pointing
					# at this router.
					other_router = router.connections[input_port]
					self.assertIn( topology.opposite(input_port)
					             , other_router.routes[route][1]
					             )
				
				# Test all outputs have a coresponding input in another router/core
				for output_port in output_ports:
					if output_port in model.Router.INTERNAL_PORTS:
						# If a route is to a core, make sure the core knows about it
						core = router.connections[output_port]
						self.assertIn(route, core.sinks)
					else:
						# Check the corresponding router has an input for this route pointing
						# from this router.
						other_router = router.connections[output_port]
						self.assertEqual( topology.opposite(output_port)
						                , other_router.routes[route][0]
						                )
Ejemplo n.º 19
0
	def __init__( self
	            , scheduler
	            , system
	            
	            , link_send_cycles        # SilistixLink
	            , link_ack_cycles         # SilistixLink
	            
	            , injection_buffer_length # SpiNNaker101
	            
	            , router_period           # SpiNNakerRouter
	            , wait_before_emergency   # SpiNNakerRouter
	            , wait_before_drop        # SpiNNakerRouter
	            
	            , core_period             # SpiNNakerTrafficGenerator
	            , packet_prob             # SpiNNakerTrafficGenerator
	            , distance_std = None     # SpiNNakerTrafficGenerator
	            ):
		"""
		link_send_cycles see SilistixLink
		link_ack_cycles see SilistixLink
		
		injection_buffer_length see SpiNNaker101
		
		router_period see SpiNNakerRouter
		wait_before_emergency see SpiNNakerRouter
		wait_before_drop see SpiNNakerRouter
		
		core_period see SpiNNakerTrafficGenerator
		packet_prob see SpiNNakerTrafficGenerator
		distance_std see SpiNNakerTrafficGenerator
		"""
		
		self.scheduler               = scheduler
		self.system                  = system
		
		# A dictionary { (x,y): SpiNNaker101, ... } of all contained chips. The
		# coordinates are relative to the central chip (created first in the
		# hexagon).
		self.chips = { }
		
		# Utility function to add a new chip to the chips dict.
		def add_chip(position):
			"Add a chip at the specified position"
			self.chips[position] = SpiNNaker101( self.scheduler
			                                   , self.system
			                                   , injection_buffer_length
			                                   , router_period
			                                   , wait_before_emergency
			                                   , wait_before_drop
			                                   , core_period
			                                   , packet_prob
			                                   , distance_std
			                                   )
		# Create the chips in a hexagonal pattern
		for position in topology.hexagon(4):
			add_chip(position)
		
		# Put SilistixLinks between them
		for src_pos, src_chip in self.chips.iteritems():
			# Try and link this chip to all other neighbours which are towards the
			# top/right of the chip
			for direction in (topology.NORTH, topology.NORTH_EAST, topology.EAST):
				dst_pos = topology.to_xy(
					topology.add_direction(topology.zero_pad(src_pos), direction))
				
				# If the chip exists, put links in this direction
				if dst_pos in self.chips:
					dst_chip = self.chips[dst_pos]
					
					in_link  = SilistixLink(self.scheduler, link_send_cycles, link_ack_cycles)
					out_link = SilistixLink(self.scheduler, link_send_cycles, link_ack_cycles)
					
					src_chip.set_out_link(direction, out_link)
					src_chip.set_in_link(direction, in_link)
					
					dst_chip.set_in_link(topology.opposite(direction), out_link)
					dst_chip.set_out_link(topology.opposite(direction), in_link)
Ejemplo n.º 20
0
	def __init__( self
	            , scheduler
	            , system
	            
	            , width
	            , height
	            
	            , use_sata_links
	            
	            , sata_accept_period      # SATALink
	            , sata_buffer_length      # SATALink
	            , sata_latency            # SATALink
	            
	            , silistix_send_cycles    # SilistixLink
	            , silistix_ack_cycles     # SilistixLink
	            
	            , injection_buffer_length # SpiNNaker101
	            
	            , router_period           # SpiNNakerRouter
	            , wait_before_emergency   # SpiNNakerRouter
	            , wait_before_drop        # SpiNNakerRouter
	            
	            , core_period             # SpiNNakerTrafficGenerator
	            , packet_prob             # SpiNNakerTrafficGenerator
	            , distance_std = None     # SpiNNakerTrafficGenerator
	            ):
		"""
		width is the number of three-board board-sets wide the system will be.
		
		height is the number of three-board board-sets tall the system will be.
		
		use_sata_links is a decision whether or not to use sata links to connect
		boards. If false, regular links are used.
		
		sata_accept_period see SATALink
		sata_buffer_length see SATALink
		sata_latency see SATALink
		
		silistix_send_cycles see SilistixLink
		silistix_ack_cycles see SilistixLink
		
		injection_buffer_length see SpiNNaker101
		
		router_period see SpiNNakerRouter
		wait_before_emergency see SpiNNakerRouter
		wait_before_drop see SpiNNakerRouter
		
		core_period see SpiNNakerTrafficGenerator
		packet_prob see SpiNNakerTrafficGenerator
		distance_std see SpiNNakerTrafficGenerator
		"""
		
		self.scheduler               = scheduler
		self.system                  = system
		
		self.width  = width
		self.height = height
		
		# A dictionary { (x,y): SpiNNaker103, ... } of all contained boards. The
		# coordinates are relative to the bottom-leftmost board (which is not
		# wrapped around). A full board is two units wide and two units tall in this
		# coordinate system.
		self.boards = { }
		
		# The size of the mesh of chips: twelve chips per board set
		mesh_dimensions = (self.width * 12, self.height * 12)
		
		# Initially create all the boards
		for y in range(self.height):
			for x in range(self.width):
				# z is the index of the board within the set. 0 is the bottom left, 1 is
				# the top, 2 is the right
				for z in range(3):
					# Odd-rows start offset by one unit right, odd columns start offset one
					# unit up.
					board = SpiNNaker103( scheduler
					                    , system
					                    , silistix_send_cycles
					                    , silistix_ack_cycles
					                    , injection_buffer_length
					                    , router_period
					                    , wait_before_emergency
					                    , wait_before_drop
					                    , core_period
					                    , packet_prob
					                    , distance_std
					                    )
					
					# The coordinates of a board within the set of boards
					x_coord = x*3 + z
					y_coord = y*3 + (3-z)%3
					self.boards[(x_coord, y_coord)] = board
					
					# Set the board's position in terms of the whole system
					board.set_mesh_dimensions(*mesh_dimensions)
					x_mesh_coord = x_coord*4
					y_mesh_coord = y_coord*4
					board.set_mesh_position(x_mesh_coord, y_mesh_coord)
					
					# If the board is on a right/top edge, the right/top half of its chips are
					# actually on the left-hand-side/bottom of the system
					if x_coord == (self.width*3)-1:
						board.set_mesh_position_right(0, y_mesh_coord)
					if y_coord == (self.height*3)-1:
						# Plus one is due to the bottom edge of the hexagons being longer than
						# the left-edge
						board.set_mesh_position_top(x_mesh_coord+1, 0)
		
		# Now link every board with all those above and to the right
		for board_coords, board in self.boards.iteritems():
			top_board_coords = ( (board_coords[0]+1) % (self.width*3)
			                   , (board_coords[1]+2) % (self.height*3)
			                   )
			top_right_board_coords = ( (board_coords[0]+2) % (self.width*3)
			                         , (board_coords[1]+1) % (self.height*3)
			                         )
			btm_right_board_coords = ( (board_coords[0]+1) % (self.width*3)
			                         , (board_coords[1]-1) % (self.height*3)
			                         )
			
			# Create the links for these edges
			for other_coords, edge in ( (top_board_coords,       topology.EDGE_TOP)
			                          , (top_right_board_coords, topology.EDGE_TOP_RIGHT)
			                          , (btm_right_board_coords, topology.EDGE_BOTTOM_RIGHT)
			                          ):
				other_board = self.boards[other_coords]
				
				if use_sata_links:
					# From board to other_board
					in_link = SATALink( self.scheduler
					                  , 8 # num_channels
					                  , sata_accept_period
					                  , sata_buffer_length
					                  , sata_latency
					                  , silistix_send_cycles
					                  , silistix_ack_cycles
					                  )
					# From other_board to board
					out_link = SATALink( self.scheduler
					                   , 8 # num_channels
					                   , sata_accept_period
					                   , sata_buffer_length
					                   , sata_latency
					                   , silistix_send_cycles
					                   , silistix_ack_cycles
					                   )
					
					# Link up each of the channels on this edge in both directions
					for channel in range(8):
						in_channel  = in_link.get_channel_link(channel)
						out_channel = out_link.get_channel_link(channel)
						
						board.set_in_link(edge, channel,  in_channel)
						board.set_out_link(edge, channel, out_channel)
						
						other_board.set_out_link(topology.opposite(edge), channel, in_channel)
						other_board.set_in_link(topology.opposite(edge), channel,  out_channel)
				
				else:
					# Link up each of the channels on this edge in both directions with
					# SilistixLinks
					for channel in range(8):
						in_link  = SilistixLink( self.scheduler
						                       , silistix_send_cycles
						                       , silistix_ack_cycles
						                       )
						out_link = SilistixLink( self.scheduler
						                       , silistix_send_cycles
						                       , silistix_ack_cycles
						                       )
						
						board.set_in_link(edge, channel,  in_link)
						board.set_out_link(edge, channel, out_link)
						
						other_board.set_out_link(topology.opposite(edge), channel, in_link)
						other_board.set_in_link(topology.opposite(edge), channel,  out_link)