def __init__(self,
                 connection_selector,
                 ignore_chips,
                 ignore_cores,
                 max_core_id,
                 max_sdram_size=None):
        """
        :param scamp_connections: The connections to use for the interaction
        :type scamp_connections: iterable of\
                    :py:class:`spinnman.connections.abstract_classes.abstract_connection.AbstractConnection`
        """
        AbstractMultiConnectionProcess.__init__(self, connection_selector)

        self._ignore_chips = ignore_chips
        self._ignore_cores = ignore_cores
        self._max_core_id = max_core_id
        self._max_sdram_size = max_sdram_size

        # A dictionary of (x, y) -> ChipInfo
        self._chip_info = dict()

        # The machine so far
        self._machine = Machine([])

        # A dictionary of which link goes where from a chip:
        # (x, y, link) -> (x, y)
        self._link_destination = dict()

        # A queue of ChipInfo to be examined
        self._search = deque()
Exemple #2
0
    def __call__(self,
                 spalloc_server,
                 spalloc_port=22244,
                 spalloc_machine=None,
                 max_sdram_size=None,
                 max_machine_core_reduction=0):
        """
        :param str spalloc_server:
        :param int spalloc_port:
        :param str spalloc_machine:
        :param int max_sdram_size:
        :param int max_machine_core_reduction:
        :rtype: ~.Machine
        """
        with ProtocolClient(spalloc_server, spalloc_port) as client:
            machines = client.list_machines()
            # Close the context immediately; don't want to keep this particular
            # connection around as there's not a great chance of this code
            # being rerun in this process any time soon.
        max_width = None
        max_height = None
        max_area = -1

        for machine in self._filter(machines, spalloc_machine):
            # Get the width and height in chips, and logical area in chips**2
            width, height, area = self._get_size(machine)

            # The "biggest" board is the one with the most chips
            if area > max_area:
                max_area = area
                max_width = width
                max_height = height

        if max_width is None:
            raise Exception(
                "The spalloc server appears to have no compatible machines")

        n_cpus_per_chip = (Machine.max_cores_per_chip() -
                           max_machine_core_reduction)

        # Return the width and height, and make no assumption about wrap-
        # arounds or version.
        return virtual_machine(width=max_width,
                               height=max_height,
                               sdram_per_chip=max_sdram_size,
                               n_cpus_per_chip=n_cpus_per_chip,
                               validate=False)
 def test_allocate_resources_when_chip_used(self):
     router = Router([])
     sdram = SDRAM()
     empty_chip = Chip(0,
                       0, [],
                       router,
                       sdram,
                       0,
                       0,
                       "127.0.0.1",
                       virtual=False,
                       tag_ids=[1])
     machine = Machine([empty_chip], 0, 0)
     resource_tracker = ResourceTracker(machine)
     with self.assertRaises(PacmanValueError):
         resource_tracker.allocate_resources(
             ResourceContainer(sdram=SDRAMResource(1024)))
    def __init__(self, scamp_connections, ignore_chips, ignore_cores, max_core_id):
        """
        :param scamp_connections: The connections to use for the interaction
        :type scamp_connections: iterable of\
                    :py:class:`spinnman.connections.abstract_classes.abstract_connection.AbstractConnection`
        """
        AbstractMultiConnectionProcess.__init__(self, scamp_connections)

        self._ignore_chips = ignore_chips
        self._ignore_cores = ignore_cores
        self._max_core_id = max_core_id

        # A dictionary of (x, y) -> ChipInfo
        self._chip_info = dict()

        # The machine so far
        self._machine = Machine([])

        # A dictionary of which link goes where from a chip:
        # (x, y, link) -> (x, y)
        self._link_destination = dict()

        # A queue of ChipInfo to be examined
        self._search = deque()
    def check_machine_is_booted(self):

        # Check that chip 0, 0 is booted
        result, chip_0_0_data = self._read_chip(0, 0)
        if chip_0_0_data is None:
            logger.error("Could not read from 0, 0: {}", result)
            return None, None

        progress_bar = ProgressBar(
            float(chip_0_0_data.x_size * chip_0_0_data.y_size * 2),
            "Verifying Machine")

        # Go through the chips, link by link
        chip_search = deque([chip_0_0_data])
        seen_chips = OrderedDict({(0, 0): chip_0_0_data})
        link_destination = dict()
        while len(chip_search) > 0:
            chip = chip_search.pop()
            details = seen_chips[chip.x, chip.y]

            for link in range(0, 6):
                chip_data = None
                retries = 3
                while chip_data is None and retries > 0:
                    _, chip_data = self._read_chip_down_link(
                        chip.x, chip.y, link)
                    if chip_data is not None and (
                            self._ignore_chips is None
                            or not self._ignore_chips.is_chip(
                                chip_data.x, chip_data.y)):
                        link_destination[(chip.x, chip.y,
                                          link)] = (chip_data.x, chip_data.y)
                        if (chip_data.x, chip_data.y) not in seen_chips:
                            chip_search.append(chip_data)
                            seen_chips[(chip_data.x, chip_data.y)] = chip_data
                            progress_bar.update()
                    elif link in details.links_available:
                        retries -= 1
                        time.sleep(0.2)
                    else:
                        retries = 0

        # Try to read each found chip
        machine = Machine([])
        for x, y in seen_chips:
            if (self._ignore_chips is None
                    or not self._ignore_chips.is_chip(x, y)):

                # Retry up to 3 times
                retries = 3
                result = None
                chip_details = None
                while retries > 0:
                    result, chip_details = self._read_chip(x, y)
                    if chip_details is not None:
                        self._add_chip(machine, chip_details, link_destination)
                        progress_bar.update()
                        break

                    # Wait between retries
                    time.sleep(0.5)
                    retries -= 1

                # If no version could be read, the machine might be faulty
                if chip_details is None:
                    logger.warn(
                        "Could not get version from chip {}, {}: {}".format(
                            x, y, result))
                    progress_bar.update()
        progress_bar.end()

        return machine, seen_chips
class GetMachineProcess(AbstractMultiConnectionProcess):
    """ A process for getting the machine details over a set of connections
    """

    def __init__(self, scamp_connections, ignore_chips, ignore_cores, max_core_id):
        """
        :param scamp_connections: The connections to use for the interaction
        :type scamp_connections: iterable of\
                    :py:class:`spinnman.connections.abstract_classes.abstract_connection.AbstractConnection`
        """
        AbstractMultiConnectionProcess.__init__(self, scamp_connections)

        self._ignore_chips = ignore_chips
        self._ignore_cores = ignore_cores
        self._max_core_id = max_core_id

        # A dictionary of (x, y) -> ChipInfo
        self._chip_info = dict()

        # The machine so far
        self._machine = Machine([])

        # A dictionary of which link goes where from a chip:
        # (x, y, link) -> (x, y)
        self._link_destination = dict()

        # A queue of ChipInfo to be examined
        self._search = deque()

    def _make_chip(self, chip_details):
        """ Creates a chip from a ChipInfo structure

        :param chip_details: The ChipInfo structure to create the chip\
                    from
        :type chip_details: \
                    :py:class:`spinnman.model.chip_info.ChipInfo`
        :return: The created chip
        :rtype: :py:class:`spinn_machine.chip.Chip`
        """

        # Create the processor list
        processors = list()
        for virtual_core_id in chip_details.virtual_core_ids:
            if self._ignore_cores is not None and self._ignore_cores.is_core(
                chip_details.x, chip_details.y, virtual_core_id
            ):
                continue
            if self._max_core_id is not None and virtual_core_id > self._max_core_id:
                continue

            processors.append(Processor(virtual_core_id, chip_details.cpu_clock_mhz * 1000000, virtual_core_id == 0))

        # Create the router - add the links later during search
        router = Router(
            links=list(),
            emergency_routing_enabled=False,
            clock_speed=Router.ROUTER_DEFAULT_CLOCK_SPEED,
            n_available_multicast_entries=(
                Router.ROUTER_DEFAULT_AVAILABLE_ENTRIES - chip_details.first_free_router_entry
            ),
        )

        # Create the chip
        chip = Chip(
            x=chip_details.x,
            y=chip_details.y,
            processors=processors,
            router=router,
            sdram=SDRAM(
                user_base_address=chip_details.sdram_base_address,
                system_base_address=chip_details.system_sdram_base_address,
            ),
            ip_address=chip_details.ip_address,
            nearest_ethernet_x=chip_details.nearest_ethernet_x,
            nearest_ethernet_y=chip_details.nearest_ethernet_y,
        )
        return chip

    def _receive_chip_details(self, scp_read_memory_response):
        try:
            new_chip_details = ChipInfo(scp_read_memory_response.data, scp_read_memory_response.offset)
            if self._ignore_chips is not None and self._ignore_chips.is_chip(new_chip_details.x, new_chip_details.y):
                return None
            key = (new_chip_details.x, new_chip_details.y)
            if key not in self._chip_info:
                self._chip_info[key] = new_chip_details
                self._search.append(new_chip_details)
                new_chip = self._make_chip(new_chip_details)
                self._machine.add_chip(new_chip)
                return new_chip
            return self._machine.get_chip_at(new_chip_details.x, new_chip_details.y)
        except Exception:
            traceback.print_exc()

    def _receive_chip_details_from_link(self, scp_read_link_response, source_x, source_y, link):
        new_chip = self._receive_chip_details(scp_read_link_response)
        if new_chip is not None:
            self._link_destination[(source_x, source_y, link)] = new_chip

    def _receive_error(self, request, exception, tracebackinfo):

        # If we get an SCPReadLinkRequest with a
        # SpinnmanUnexpectedResponseCodeException, this is a failed link
        # and so can be ignored
        if not isinstance(request, SCPReadLinkRequest) or not isinstance(
            exception, SpinnmanUnexpectedResponseCodeException
        ):
            AbstractProcess._receive_error(self, request, exception, tracebackinfo)

    def get_machine_details(self):

        # Get the details of chip 0, 0
        self._send_request(
            SCPReadMemoryRequest(
                x=0, y=0, base_address=constants.SYSTEM_VARIABLE_BASE_ADDRESS, size=constants.SYSTEM_VARIABLE_BYTES
            ),
            self._receive_chip_details,
            self._receive_error,
        )
        self._finish()

        # Continue until there is nothing to search (and no exception)
        while not self.is_error() and len(self._search) > 0:

            # Set up the next round of searches using everything that
            # needs to search (same loop as above, I know, but wait for it)
            while not self.is_error() and len(self._search) > 0:
                chip_info = self._search.pop()

                # Examine the links of the chip to find the next chips
                for link in chip_info.links_available:

                    # Add the read_link request - note that this might
                    # add to the search if a response is received
                    receiver = _ChipInfoReceiver(self, chip_info.x, chip_info.y, link)
                    self._send_request(
                        SCPReadLinkRequest(
                            x=chip_info.x,
                            y=chip_info.y,
                            cpu=0,
                            link=link,
                            base_address=(constants.SYSTEM_VARIABLE_BASE_ADDRESS),
                            size=constants.SYSTEM_VARIABLE_BYTES,
                        ),
                        receiver._receive_chip_details,
                        self._receive_error,
                    )

            # Ensure all responses up to this point have been received
            self._finish()

        # If there is an exception, raise it
        self.check_for_error()

        # We now have all the chip details, now link them up and make a machine
        # Start by making a queue of (chip, link ids) to search, starting at
        # 0, 0
        chip_0_0_info = self._chip_info[(0, 0)]
        chip_0_0 = self._machine.get_chip_at(0, 0)
        chip_search = deque([(chip_0_0, chip_0_0_info.links_available)])

        # Go through the chips, link by link
        seen_chips = set()
        seen_chips.add((0, 0))
        while len(chip_search) > 0:
            chip, links = chip_search.pop()

            # Go through the links of the chip
            for link in links:

                # Only continue if the chip link worked
                if (chip.x, chip.y, link) in self._link_destination:

                    other_chip = self._link_destination[(chip.x, chip.y, link)]

                    # Standard links use the opposite link id (with ids between
                    # 0 and 5) as default
                    opposite_link_id = (link + 3) % 6

                    # Check that the other chip link worked in reverse
                    if (other_chip.x, other_chip.y, opposite_link_id) in self._link_destination:

                        # Add the link to this chip
                        chip.router.add_link(
                            Link(chip.x, chip.y, link, other_chip.x, other_chip.y, opposite_link_id, opposite_link_id)
                        )

                        # If the chip is not already seen, add it to the search
                        if (other_chip.x, other_chip.y) not in seen_chips:
                            other_chip_details = self._chip_info[(other_chip.x, other_chip.y)]
                            chip_search.append((other_chip, other_chip_details.links_available))
                            seen_chips.add((other_chip.x, other_chip.y))

        return self._machine

    def get_chip_info(self):
        """ Get the chip information for the machine.  Note that\
            get_machine_details must have been called first
        """
        return self._chip_info
class GetMachineProcess(AbstractMultiConnectionProcess):
    """ A process for getting the machine details over a set of connections
    """
    def __init__(self,
                 connection_selector,
                 ignore_chips,
                 ignore_cores,
                 max_core_id,
                 max_sdram_size=None):
        """
        :param scamp_connections: The connections to use for the interaction
        :type scamp_connections: iterable of\
                    :py:class:`spinnman.connections.abstract_classes.abstract_connection.AbstractConnection`
        """
        AbstractMultiConnectionProcess.__init__(self, connection_selector)

        self._ignore_chips = ignore_chips
        self._ignore_cores = ignore_cores
        self._max_core_id = max_core_id
        self._max_sdram_size = max_sdram_size

        # A dictionary of (x, y) -> ChipInfo
        self._chip_info = dict()

        # The machine so far
        self._machine = Machine([])

        # A dictionary of which link goes where from a chip:
        # (x, y, link) -> (x, y)
        self._link_destination = dict()

        # A queue of ChipInfo to be examined
        self._search = deque()

    def _make_chip(self, chip_details):
        """ Creates a chip from a ChipInfo structure

        :param chip_details: The ChipInfo structure to create the chip\
                    from
        :type chip_details: \
                    :py:class:`spinnman.model.chip_info.ChipInfo`
        :return: The created chip
        :rtype: :py:class:`spinn_machine.chip.Chip`
        """

        # Create the processor list
        processors = list()
        for virtual_core_id in chip_details.virtual_core_ids:
            if (self._ignore_cores is not None and self._ignore_cores.is_core(
                    chip_details.x, chip_details.y, virtual_core_id)):
                continue
            if (self._max_core_id is not None
                    and virtual_core_id > self._max_core_id):
                continue

            processors.append(
                Processor(virtual_core_id,
                          chip_details.cpu_clock_mhz * 1000000,
                          virtual_core_id == 0))

        # Create the router - add the links later during search
        router = Router(links=list(),
                        emergency_routing_enabled=False,
                        clock_speed=Router.ROUTER_DEFAULT_CLOCK_SPEED,
                        n_available_multicast_entries=(
                            Router.ROUTER_DEFAULT_AVAILABLE_ENTRIES -
                            chip_details.first_free_router_entry))

        # Create the chip's SDRAM object
        sdram = None
        if self._max_sdram_size is not None:
            size = (chip_details.system_sdram_base_address -
                    chip_details.sdram_heap_address)
            if size > self._max_sdram_size:
                system_base_address = \
                    chip_details.sdram_heap_address + self._max_sdram_size
                sdram = SDRAM(
                    user_base_address=chip_details.sdram_heap_address,
                    system_base_address=system_base_address)
            else:
                sdram = SDRAM(
                    user_base_address=chip_details.sdram_heap_address,
                    system_base_address=chip_details.system_sdram_base_address)
        else:
            sdram = SDRAM(
                user_base_address=chip_details.sdram_heap_address,
                system_base_address=chip_details.system_sdram_base_address)

        # Create the chip
        chip = Chip(x=chip_details.x,
                    y=chip_details.y,
                    processors=processors,
                    router=router,
                    sdram=sdram,
                    ip_address=chip_details.ip_address,
                    nearest_ethernet_x=chip_details.nearest_ethernet_x,
                    nearest_ethernet_y=chip_details.nearest_ethernet_y)

        # reset params for next iteration
        self._chip_x = None
        self._chip_y = None
        self._heap_address = None
        self._heap_size = None
        return chip

    def _receive_chip_details(self, scp_read_memory_response):
        try:
            new_chip_details = ChipInfo(scp_read_memory_response.data,
                                        scp_read_memory_response.offset)
            if (self._ignore_chips is not None and self._ignore_chips.is_chip(
                    new_chip_details.x, new_chip_details.y)):
                return None
            key = (new_chip_details.x, new_chip_details.y)
            if key not in self._chip_info:
                self._chip_info[key] = new_chip_details
                self._search.append(new_chip_details)
                new_chip = self._make_chip(new_chip_details)
                self._machine.add_chip(new_chip)
                return new_chip
            return self._machine.get_chip_at(new_chip_details.x,
                                             new_chip_details.y)
        except Exception:
            traceback.print_exc()

    def _receive_chip_details_from_link(self, scp_read_link_response, source_x,
                                        source_y, link):
        new_chip = self._receive_chip_details(scp_read_link_response)
        if new_chip is not None:
            self._link_destination[(source_x, source_y, link)] = new_chip

    def _receive_error(self, request, exception, tracebackinfo):

        # If we get an SCPReadLinkRequest with a
        # SpinnmanUnexpectedResponseCodeException, this is a failed link
        # and so can be ignored
        if (not isinstance(request, SCPReadLinkRequest) or not isinstance(
                exception,
                exceptions.SpinnmanUnexpectedResponseCodeException)):
            AbstractProcess._receive_error(self, request, exception,
                                           tracebackinfo)

    def get_machine_details(self):

        # Get the details of chip 0, 0
        self._send_request(
            SCPReadMemoryRequest(
                x=0,
                y=0,
                base_address=constants.SYSTEM_VARIABLE_BASE_ADDRESS,
                size=constants.SYSTEM_VARIABLE_BYTES),
            self._receive_chip_details, self._receive_error)
        self._finish()

        # Continue until there is nothing to search (and no exception)
        while not self.is_error() and len(self._search) > 0:

            # Set up the next round of searches using everything that
            # needs to search (same loop as above, I know, but wait for it)
            while not self.is_error() and len(self._search) > 0:
                chip_info = self._search.pop()

                # Examine the links of the chip to find the next chips
                for link in chip_info.links_available:

                    # Add the read_link request - note that this might
                    # add to the search if a response is received
                    receiver = _ChipInfoReceiver(self, chip_info.x,
                                                 chip_info.y, link)
                    self._send_request(
                        SCPReadLinkRequest(
                            x=chip_info.x,
                            y=chip_info.y,
                            cpu=0,
                            link=link,
                            base_address=(
                                constants.SYSTEM_VARIABLE_BASE_ADDRESS),
                            size=constants.SYSTEM_VARIABLE_BYTES),
                        receiver._receive_chip_details, self._receive_error)

            # Ensure all responses up to this point have been received
            self._finish()

        # If there is an exception, raise it
        self.check_for_error()

        # We now have all the chip details, now link them up and make a machine
        # Start by making a queue of (chip, link ids) to search, starting at
        # 0, 0
        chip_0_0_info = self._chip_info[(0, 0)]
        chip_0_0 = self._machine.get_chip_at(0, 0)
        chip_search = deque([(chip_0_0, chip_0_0_info.links_available)])

        # Go through the chips, link by link
        seen_chips = set()
        seen_chips.add((0, 0))
        while len(chip_search) > 0:
            chip, links = chip_search.pop()

            # Go through the links of the chip
            for link in links:

                # Only continue if the chip link worked
                if (chip.x, chip.y, link) in self._link_destination:

                    other_chip = self._link_destination[(chip.x, chip.y, link)]

                    # Standard links use the opposite link id (with ids between
                    # 0 and 5) as default
                    opposite_link_id = (link + 3) % 6

                    # Check that the other chip link worked in reverse
                    if ((other_chip.x, other_chip.y, opposite_link_id)
                            in self._link_destination):

                        # Add the link to this chip
                        chip.router.add_link(
                            Link(chip.x, chip.y, link, other_chip.x,
                                 other_chip.y, opposite_link_id,
                                 opposite_link_id))

                        # If the chip is not already seen, add it to the search
                        if (other_chip.x, other_chip.y) not in seen_chips:
                            other_chip_details = self._chip_info[(
                                other_chip.x, other_chip.y)]
                            chip_search.append(
                                (other_chip,
                                 other_chip_details.links_available))
                            seen_chips.add((other_chip.x, other_chip.y))

        return self._machine

    def get_chip_info(self):
        """ Get the chip information for the machine.  Note that\
            get_machine_details must have been called first
        """
        return self._chip_info
    def __init__(
            self, width=None, height=None, with_wrap_arounds=False,
            version=None, n_cpus_per_chip=18, with_monitors=True,
            sdram_per_chip=None):
        """

        :param width: the width of the virtual machine in chips
        :type width: int
        :param height: the height of the virtual machine in chips
        :type height: int
        :param with_wrap_arounds: bool defining if wrap around links exist
        :type with_wrap_arounds: bool
        :param version: the version id of a board; if None, a machine is\
                    created with the correct dimensions, otherwise the machine\
                    will be a single board of the given version
        :type version: int
        :param n_cpus_per_chip: The number of CPUs to put on each chip
        :type n_cpus_per_chip: int
        :param with_monitors: True if CPU 0 should be marked as a monitor
        :type with_monitors: bool
        :param sdram_per_chip: The amount of SDRAM to give to each chip
        :type sdram_per_chip: int or None
        """
        Machine.__init__(self, ())

        if ((width is not None and width < 0) or
                (height is not None and height < 0)):
            raise exceptions.SpinnMachineInvalidParameterException(
                "width or height", "{} or {}".format(width, height),
                "Negative dimensions are not supported")

        if version is None and (width is None or height is None):
            raise exceptions.SpinnMachineInvalidParameterException(
                "version, width, height",
                "{}, {}, {}".format(version, width, height),
                "Either version must be specified, "
                "or width and height must both be specified")

        if version is not None and (version < 2 or version > 5):
            raise exceptions.SpinnMachineInvalidParameterException(
                "version", str(version),
                "Version must be between 2 and 5 inclusive or None")

        if ((version == 5 or version == 4) and
                with_wrap_arounds is not None and with_wrap_arounds):
            raise exceptions.SpinnMachineInvalidParameterException(
                "version and with_wrap_arounds",
                "{} and True".format(version),
                "A version {} board does not have wrap arounds; set "
                "version to None or with_wrap_arounds to None".format(version))

        if (version == 2 or version == 3) and with_wrap_arounds is not None:
            raise exceptions.SpinnMachineInvalidParameterException(
                "version and with_wrap_arounds",
                "{} and {}".format(version, with_wrap_arounds),
                "A version {} board has complex wrap arounds; set "
                "version to None or with_wrap_arounds to None".format(version))

        if ((version == 5 or version == 4) and (
                (width is not None and width != 8) or
                (height is not None and height != 8))):
            raise exceptions.SpinnMachineInvalidParameterException(
                "version, width, height",
                "{}, {}, {}".format(version, width, height),
                "A version {} board has a width and height of 8; set "
                "version to None or width and height to None".format(version))

        if ((version == 2 or version == 3) and (
                (width is not None and width != 2) or
                (height is not None and height != 2))):
            raise exceptions.SpinnMachineInvalidParameterException(
                "version, width, height",
                "{}, {}, {}".format(version, width, height),
                "A version {} board has a width and height of 2; set "
                "version to None or width and height to None".format(version))

        if version == 5 or version == 4:
            if width is None:
                width = 8
            if height is None:
                height = 8
            with_wrap_arounds = False
        if version == 2 or version == 3:
            if width is None:
                width = 2
            if height is None:
                height = 2
            with_wrap_arounds = True

        # if x and y are none, assume a 48 chip board
        logger.debug("width = {} and height  = {}".format(width, height))

        # calculate the chip ids which this machine is going to have
        chip_ids = list()
        for i in xrange(width):
            for j in xrange(height):
                coords = (i, j)
                if (version == 5 and width == 8 and height == 8 and
                        coords in _48boardgaps):

                    # a chip doesn't exist in this static position
                    # on these boards, so nullify it
                    pass
                else:
                    chip_ids.append((i, j))

        progress_bar = ProgressBar(
            width * height, "Generating a virtual machine")

        # Create the chips and their links
        for i in xrange(width):
            for j in xrange(height):
                coords = (i, j)
                if (version == 5 and width == 8 and height == 8 and
                        coords in _48boardgaps):

                    # a chip doesn't exist in this static position
                    # on these boards, so nullify it
                    pass
                else:
                    processors = list()
                    for processor_id in range(0, n_cpus_per_chip):
                        processor = Processor(processor_id, 200000000)
                        if processor_id == 0 and with_monitors:
                            processor.is_monitor = True
                        processors.append(processor)
                    chip_links = self._calculate_links(
                        i, j, width, height, with_wrap_arounds, version,
                        chip_ids)
                    chip_router = Router(chip_links, False)
                    if sdram_per_chip is None:
                        sdram = SDRAM()
                    else:
                        system_base_address = (
                            SDRAM.DEFAULT_BASE_ADDRESS + sdram_per_chip)
                        sdram = SDRAM(system_base_address=system_base_address)

                    chip = Chip(i, j, processors, chip_router, sdram, 0, 0,
                                "127.0.0.1")
                    self.add_chip(chip)

                progress_bar.update()

        progress_bar.end()

        processor_count = 0
        for chip in self.chips:
            processor_count += len(list(chip.processors))

        link_count = 0
        for chip in self.chips:
            link_count += len(list(chip.router.links))

        logger.debug(
            "Static Allocation Complete;"
            " {} calculated app cores and {} links!".format(
                processor_count, link_count))