Exemplo n.º 1
0
    def __init__(self, version_data, offset=0):
        """
        :param bytes version_data:
            bytes from an SCP packet containing version information
        :param int offset:
            the offset in the bytes from an SCP packet containing
            version information
        :raise SpinnmanInvalidParameterException:
            If the message does not contain valid version information
        """
        (self._p, self._physical_cpu_id, self._y, self._x, _,
            version_no, self._build_date) = _VERSION_PATTERN.unpack_from(
                memoryview(version_data), offset)

        version_data = version_data[offset + 12:-1].decode("utf-8")

        if version_no < 0xFFFF:
            try:
                self._version_number = (version_no // 100, version_no % 100, 0)
                self._name, self._hardware = version_data.split("/")
                self._version_string = version_data
            except ValueError as exception:
                raise SpinnmanInvalidParameterException(
                    "version_data", version_data,
                    "Incorrect format: {}".format(exception)) from exception
        else:
            name_hardware, _, version = version_data.partition("\0")
            self._version_string = version
            matches = re.match(r"(\d+)\.(\d+)\.(\d+)", version)
            if matches is None:
                raise SpinnmanInvalidParameterException(
                    "version", version, "Cannot be parsed")
            self._version_number = tuple(map(int, matches.group(1, 2, 3)))
            self._name, self._hardware = name_hardware.rstrip("\0").split("/")
 def get_bytestring(self, eieio_type):
     if eieio_type.payload_bytes == 0:
         raise SpinnmanInvalidParameterException(
             "eieio_type", eieio_type,
             "The type specifies no payload, but this element has a "
             "payload")
     if eieio_type == EIEIOType.KEY_PAYLOAD_16_BIT:
         return _TWO_SHORTS.pack(self._key, self._payload)
     elif eieio_type == EIEIOType.KEY_PAYLOAD_32_BIT:
         return _TWO_WORDS.pack(self._key, self._payload)
     else:
         raise SpinnmanInvalidParameterException(
             "eieio_type", eieio_type, "Unknown type")
 def get_bytestring(self, eieio_type):
     if eieio_type.payload_bytes != 0:
         raise SpinnmanInvalidParameterException(
             "eieio_type", eieio_type,
             "The type specifies a payload, but this element has no"
             " payload")
     if eieio_type == EIEIOType.KEY_16_BIT:
         return struct.pack("<H", self._key)
     elif eieio_type == EIEIOType.KEY_32_BIT:
         return struct.pack("<I", self._key)
     else:
         raise SpinnmanInvalidParameterException("eieio_type", eieio_type,
                                                 "Unknown type")
Exemplo n.º 4
0
    def __init__(self, x, y, n_entries, table_address, base_address, app_id):
        """

        :param x: The x-coordinate of the chip, between 0 and 255, \
        this is not checked due to speed restrictions
        :type x: int
        :param y: The y-coordinate of the chip, between 0 and 255\
        this is not checked due to speed restrictions
        :type y: int
        :param n_entries: The number of entries in the table, more than 0
        :type n_entries: int
        :param table_address: The allocated table address
        :type table_address: int
        :param base_address: The base_address containing the entries
        :type base_address: int
        :param app_id: The id of the application with which to associate the\
                    routes.  If not specified, defaults to 0.
        :type app_id: int
        :raise spinnman.exceptions.SpinnmanInvalidParameterException:\
                    * If x is out of range
                    * If y is out of range
                    * If n_entries is 0 or less
                    * If table_address is not positive
                    * If base_address is not positive
        """
        if n_entries < 1:
            raise SpinnmanInvalidParameterException("n_entries",
                                                    str(n_entries),
                                                    "Must be more than 0")
        if base_address < 0:
            raise SpinnmanInvalidParameterException(
                "base_address", str(base_address),
                "Must be a positive integer")
        if table_address < 0:
            raise SpinnmanInvalidParameterException(
                "table_address", str(table_address),
                "Must be a positive integer")

        super(SCPRouterInitRequest, self).__init__(
            SDPHeader(flags=SDPFlag.REPLY_EXPECTED,
                      destination_port=0,
                      destination_cpu=0,
                      destination_chip_x=x,
                      destination_chip_y=y),
            SCPRequestHeader(command=SCPCommand.CMD_RTR),
            argument_1=((n_entries << 16) | (app_id << 8) | 2),
            argument_2=table_address,
            argument_3=base_address)
Exemplo n.º 5
0
 def malloc_sdram(self, x, y, size, app_id, tag):
     space_required = size + 8
     heap = self._get_heap(x, y,
                           SystemVariableDefinition.sdram_heap_address)
     space = None
     index = None
     for i, element in enumerate(heap):
         if element.is_free and element.size >= space_required:
             space = element
             index = i
             break
     if space is None:
         raise SpinnmanInvalidParameterException(
             "SDRAM Allocation response base address", 0,
             "Could not allocate {} bytes of SDRAM".format(size))
     free = 0xFFFF0000 | (app_id << 8) | tag
     next_space = None
     if index + 1 < len(heap):
         next_space = heap[index + 1]
     else:
         next_space = HeapElement(space.next_address, space.next_address,
                                  0xFFFFFFFF)
     heap.pop(index)
     if space.size > space_required:
         new_space = HeapElement(space.block_address + space_required,
                                 space.next_address, 0x00000000)
         next_space = new_space
         heap.insert(index, new_space)
     heap.insert(
         index,
         HeapElement(space.block_address, next_space.block_address, free))
     return space.block_address
Exemplo n.º 6
0
    def __init__(self,
                 opcode,
                 operand_1,
                 operand_2,
                 operand_3,
                 data=None,
                 offset=0):
        """
        :param SpinnakerBootOpCode opcode: The operation of this packet
        :param int operand_1: The first operand
        :param int operand_2: The second operand
        :param int operand_3: The third operand
        :param data: The optional data, up to 256 words
        :type data: bytes or bytearray
        :param int offset: The offset of the valid data
        :raise SpinnmanInvalidParameterException:
            If the opcode is not a valid value
        """
        # pylint: disable=too-many-arguments
        if data is not None and len(data) > (256 * 4):
            raise SpinnmanInvalidParameterException(
                "len(data)", str(len(data)),
                "A boot packet can contain at most 256 words of data")

        self._opcode = opcode
        self._operand_1 = operand_1
        self._operand_2 = operand_2
        self._operand_3 = operand_3
        self._data = data
        self._offset = offset
    def __init__(self,
                 opcode,
                 operand_1,
                 operand_2,
                 operand_3,
                 data=None,
                 offset=0):
        """
        :param opcode: The operation of this packet
        :type opcode:\
                    :py:class:`spinnman.messages.spinnaker_boot.spinnaker_boot_op_code.SpinnakerBootOpCode`
        :param operand_1: The first operand
        :type operand_1: int
        :param operand_2: The second operand
        :type operand_2: int
        :param operand_3: The third operand
        :type operand_3: int
        :param data: The optional data, up to 256 words
        :type data: bytestring
        :param offset: The offset of the valid data
        :type offset: int
        :raise spinnman.exceptions.SpinnmanInvalidParameterException: If the\
                    opcode is not a valid value
        """
        if data is not None and len(data) > (256 * 4):
            raise SpinnmanInvalidParameterException(
                "len(data)", str(len(data)),
                "A boot packet can contain at most 256 words of data")

        self._opcode = opcode
        self._operand_1 = operand_1
        self._operand_2 = operand_2
        self._operand_3 = operand_3
        self._data = data
        self._offset = offset
Exemplo n.º 8
0
    def __init__(self, app_id, signal):
        """

        :param app_id: The id of the application, between 0 and 255
        :type app_id: int
        :param signal: The signal to send
        :type signal: :py:class:`spinnman.messages.scp.scp_signal.SCPSignal`
        :raise spinnman.exceptions.SpinnmanInvalidParameterException: If\
            app_id is out of range
        """

        if app_id < 0 or app_id > 255:
            raise SpinnmanInvalidParameterException(
                "app_id", str(app_id), "Must be between 0 and 255")

        super(SCPSendSignalRequest,
              self).__init__(SDPHeader(flags=SDPFlag.REPLY_EXPECTED,
                                       destination_port=0,
                                       destination_cpu=0,
                                       destination_chip_x=0,
                                       destination_chip_y=0),
                             SCPRequestHeader(command=SCPCommand.CMD_SIG),
                             argument_1=signal.signal_type.value,
                             argument_2=_get_data(app_id, signal),
                             argument_3=_ALL_CORE_MASK)
 def __init__(self, command):
     if isinstance(command, Enum):
         command = command.value
     if command < 0 or command >= 16384:
         raise SpinnmanInvalidParameterException(
             "command", command,
             "parameter command is outside the allowed range (0 to 16383)")
     self._command = command
Exemplo n.º 10
0
    def __init__(self, eieio_header, data=None, offset=0):
        EIEIODataMessage.__init__(self, eieio_header, data, offset)

        if eieio_header.eieio_type.payload_bytes == 0:
            raise SpinnmanInvalidParameterException(
                "eieio_header", eieio_header,
                "This message should have a payload, but the header indicates"
                " that it doesn't")
    def add_key_and_payload(self, key, payload):
        """ Adds a key and payload to the packet

        :param int key: The key to add
        :param int payload: The payload to add
        :raise SpinnmanInvalidParameterException:
            If the key or payload is too big for the format, or the format
            doesn't expect a payload
        """
        if key > self._header.eieio_type.max_value:
            raise SpinnmanInvalidParameterException(
                "key", key, "Larger than the maximum allowed of {}".format(
                    self._header.eieio_type.max_value))
        if payload > self._header.eieio_type.max_value:
            raise SpinnmanInvalidParameterException(
                "payload", payload,
                "Larger than the maximum allowed of {}".format(
                    self._header.eieio_type.max_value))

        self.add_element(
            KeyPayloadDataElement(key, payload, self._header.is_time))
Exemplo n.º 12
0
    def __init__(self, x, y, n_entries, table_address, base_address, app_id):
        """
        :param int x: The x-coordinate of the chip, between 0 and 255
        :param int y: The y-coordinate of the chip, between 0 and 255
        :param int n_entries: The number of entries in the table, more than 0
        :param int table_address: The allocated table address
        :param int base_address: The base_address containing the entries
        :param int app_id:
            The ID of the application with which to associate the
            routes.  If not specified, defaults to 0.
        :raise SpinnmanInvalidParameterException:
            * If x is out of range
            * If y is out of range
            * If n_entries is 0 or less
            * If table_address is not positive
            * If base_address is not positive
        """
        # pylint: disable=too-many-arguments
        if n_entries < 1:
            raise SpinnmanInvalidParameterException("n_entries",
                                                    str(n_entries),
                                                    "Must be more than 0")
        if base_address < 0:
            raise SpinnmanInvalidParameterException(
                "base_address", str(base_address),
                "Must be a positive integer")
        if table_address < 0:
            raise SpinnmanInvalidParameterException(
                "table_address", str(table_address),
                "Must be a positive integer")

        super().__init__(SDPHeader(flags=SDPFlag.REPLY_EXPECTED,
                                   destination_port=0,
                                   destination_cpu=0,
                                   destination_chip_x=x,
                                   destination_chip_y=y),
                         SCPRequestHeader(command=SCPCommand.CMD_RTR),
                         argument_1=((n_entries << 16) | (app_id << 8) | 2),
                         argument_2=table_address,
                         argument_3=base_address)
Exemplo n.º 13
0
    def read_data_bytestring(self, data, offset):
        result = self.scp_response_header.result
        if result != SCPResult.RC_OK:
            raise SpinnmanUnexpectedResponseCodeException(
                "SDRAM Allocation", "CMD_ALLOC", result.name)
        self._base_address = _ONE_WORD.unpack_from(data, offset)[0]

        # check that the base address is not null (0 in python case) as
        # this reflects a issue in the command on SpiNNaker side
        if self._base_address == 0:
            raise SpinnmanInvalidParameterException(
                "SDRAM Allocation response base address", self._base_address,
                "Could not allocate {} bytes of SDRAM".format(self._size))
    def add_key(self, key):
        """ Add a key to the packet

        :param key: The key to add
        :type key: int
        :raise SpinnmanInvalidParameterException: If the key is too\
                    big for the format
        """
        if key > self._eieio_header.eieio_type.max_value:
            raise SpinnmanInvalidParameterException(
                "key", key, "Larger than the maximum allowed of {}".format(
                    self._eieio_header.eieio_type.max_value))
        EIEIODataMessage.add_element(self, EIEIOKeyDataElement(key))
    def add_key(self, key):
        """ Add a key to the packet

        :param int key: The key to add
        :raise SpinnmanInvalidParameterException:
            If the key is too big for the format, or the format expects a
            payload
        """
        if key > self._header.eieio_type.max_value:
            raise SpinnmanInvalidParameterException(
                "key", key, "Larger than the maximum allowed of {}".format(
                    self._header.eieio_type.max_value))
        self.add_element(KeyDataElement(key))
Exemplo n.º 16
0
    def add_key_and_payload(self, key, payload):
        """ Adds a key and payload to the packet

        :param key: The key to add
        :type key: int
        :param payload: The payload to add
        :type payload: int
        :raise SpinnmanInvalidParameterException: If the key or payload is too\
                    big for the format
        """
        if key > self._eieio_header.eieio_type.max_value:
            raise SpinnmanInvalidParameterException(
                "key", key, "Larger than the maximum allowed of {}".format(
                    self._eieio_header.eieio_type.max_value))
        if payload > self._eieio_header.eieio_type.max_value:
            raise SpinnmanInvalidParameterException(
                "payload", payload,
                "Larger than the maximum allowed of {}".format(
                    self._eieio_header.eieio_type.max_value))
        EIEIODataMessage.add_element(
            self,
            EIEIOKeyPayloadDataElement(key, payload,
                                       self._eieio_header.is_time))
Exemplo n.º 17
0
    def read_data_bytestring(self, data, offset):
        """ See\
            :py:meth:`spinnman.messages.scp.abstract_scp_response.AbstractSCPResponse.read_data_bytestring`
        """
        result = self.scp_response_header.result
        if result != SCPResult.RC_OK:
            raise SpinnmanUnexpectedResponseCodeException(
                "SDRAM Allocation", "CMD_ALLOC", result.name)
        self._base_address = struct.unpack_from("<I", data, offset)[0]

        # check that the base address is not null (0 in python case) as
        # this reflects a issue in the command on spinnaker side
        if self._base_address == 0:
            raise SpinnmanInvalidParameterException(
                "SDRAM Allocation response base address", self._base_address,
                "Could not allocate {} bytes of SDRAM".format(self._size))
    def load_routes(self, x, y, routes, app_id):
        """
        :param int x:
        :param int y:
        :param list(~spinn_machine.MulticastRoutingEntry) routes:
        :param int app_id:
        """
        # Create the routing data - 16 bytes per entry plus one for the end
        # entry
        routing_data = bytearray(16 * (len(routes) + 1))
        n_entries = 0
        for route in routes:
            route_entry = \
                Router.convert_routing_table_entry_to_spinnaker_route(route)

            _ROUTE_PATTERN.pack_into(
                routing_data, n_entries * 16, n_entries,
                route_entry, route.routing_entry_key, route.mask)
            n_entries += 1

        # Add an entry to mark the end
        _END_PATTERN.pack_into(
            routing_data, n_entries * 16,
            0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)

        # Upload the data
        process = WriteMemoryProcess(self._conn_selector)
        process.write_memory_from_bytearray(
            x, y, 0, _TABLE_ADDRESS, routing_data, 0, len(routing_data))

        # Allocate space in the router table
        self._send_request(RouterAlloc(x, y, app_id, n_entries),
                           self.__handle_router_alloc_response)
        self._finish()
        self.check_for_error()
        if self._base_address == 0:
            raise SpinnmanInvalidParameterException(
                "Allocation base address", str(self._base_address),
                "Not enough space to allocate the entries")

        # Load the entries
        self._send_request(
            RouterInit(
                x, y, n_entries, _TABLE_ADDRESS, self._base_address, app_id))
        self._finish()
        self.check_for_error()
Exemplo n.º 19
0
    def add_core_subset(self, core_subset):
        """ Add a core subset to the set

        :param core_subset: The core subset to add
        :type core_subset: :py:class:`spinnman.model.core_subset.CoreSubset`
        :return: Nothing is returned
        :rtype: None
        :raise spinnman.exceptions.SpinnmanInvalidParameterException: If there\
                    is already a subset with the same core x and y\
                    coordinates
        """
        if (core_subset.x, core_subset.y) in self._core_subsets:
            raise SpinnmanInvalidParameterException(
                "core_subset.(x, y)", "{}, {}".format(core_subset.x,
                                                      core_subset.y),
                "There can be only one set of cores for each chip")
        self._core_subsets[(core_subset.x, core_subset.y)] = core_subset
    def known(self, binary, chip_x, chip_y, chip_p):
        """
        :param str binary:
        :param int chip_x:
        :param int chip_y:
        :param int chip_p:
        :rtype: bool
        """
        if not self._all_core_subsets.is_core(chip_x, chip_y, chip_p):
            return False
        # OK if and only if the chip is in this binary already
        if binary in self._targets:
            if self._targets[binary].is_core(chip_x, chip_y, chip_p):
                return True

        parameter = "x:{} y:{} p:{}".format(chip_x, chip_y, chip_p)
        problem = "Already associated with a different binary"
        raise SpinnmanInvalidParameterException(parameter, binary, problem)
    def get_cpu_info(self, chip_info, core_subsets):
        for core_subset in core_subsets:
            x = core_subset.x
            y = core_subset.y

            this_chip_info = chip_info[(x, y)]

            for p in core_subset.processor_ids:
                if p not in this_chip_info.virtual_core_ids:
                    raise SpinnmanInvalidParameterException(
                        "p", p, "Not a valid core on chip {}, {}".format(x, y))
                base_address = (this_chip_info.cpu_information_base_address +
                                (constants.CPU_INFO_BYTES * p))
                self._send_request(
                    SCPReadMemoryRequest(x, y, base_address,
                                         constants.CPU_INFO_BYTES),
                    functools.partial(self.handle_response, x, y, p))
        self._finish()
        self.check_for_error()
        return self._cpu_info
Exemplo n.º 22
0
 def __init__(self, version_data, offset=0):
     """
     :param version_data: bytes from an SCP packet containing version\
                 information
     :param offset: the offset in the bytes from an SCP packet containing
                    version information
     :type version_data: bytearray
     :raise spinnman.exceptions.SpinnmanInvalidParameterException: If the\
                 message does not contain valid version information
     """
     (self._p, self._y, self._x, version_no, self._build_date) = \
         struct.unpack_from("<BxBB2xHI", version_data, offset)
     self._version_number = version_no / 100.0
     self._version_string = version_data[offset + 12:-1].decode("ascii")
     try:
         self._name, self._hardware = self._version_string.split("/")
     except ValueError as exception:
         raise SpinnmanInvalidParameterException(
             "version_string", self._version_string,
             "Incorrect format: {}".format(exception))
Exemplo n.º 23
0
    def __init__(self, x, y, app_id, size, tag=None, retry_tag=True):
        """
        :param int x:
            The x-coordinate of the chip to allocate on, between 0 and 255
        :param int y:
            The y-coordinate of the chip to allocate on, between 0 and 255
        :param int app_id: The ID of the application, between 0 and 255
        :param int size: The size in bytes of memory to be allocated
        :param int tag:
            The tag for the SDRAM, a 8-bit (chip-wide) tag that can be
            looked up by a SpiNNaker application to discover the address of
            the allocated block. If `0` then no tag is applied.
        :param bool retry_tag:
            If a tag is used, add a safety check to retry the tag.  This can
            avoid issues with re-allocating memory on a retry message.
        """
        # pylint: disable=too-many-arguments
        extra_flag = 0
        if retry_tag and tag is not None:
            extra_flag = FLAG_RETRY_TAG

        if tag is None:
            tag = 0
        elif not(0 <= tag < 256):
            raise SpinnmanInvalidParameterException(
                "tag",
                "The tag param needs to be between 0 and 255, or None (in "
                "which case 0 will be used by default)", str(tag))

        super().__init__(
            SDPHeader(
                flags=SDPFlag.REPLY_EXPECTED, destination_port=0,
                destination_cpu=0, destination_chip_x=x,
                destination_chip_y=y),
            SCPRequestHeader(command=SCPCommand.CMD_ALLOC),
            argument_1=(
                (extra_flag << 16) |
                (app_id << 8) |
                AllocFree.ALLOC_SDRAM.value),  # @UndefinedVariable
            argument_2=size, argument_3=tag)
        self._size = size
Exemplo n.º 24
0
    def __init__(self, control_register, error_status, register_values):
        """
        :param int control_register: The value of the control register
        :param int error_status: The value of the error_status
        :param list(int) register_values:
            The values of the 16 router registers
        :raise SpinnmanInvalidParameterException:
            If the number of register values is not 16
        """
        if len(register_values) != 16:
            raise SpinnmanInvalidParameterException(
                "len(register_values)", str(len(ROUTER_REGISTER_REGISTERS)),
                "There must be exactly 16 register values")

        self._mon = (control_register >> 8) & 0x1F
        self._wait_1 = (control_register >> 16) & 0xFF
        self._wait_2 = (control_register >> 24) & 0xFF

        self._error_status = error_status

        self._register_values = register_values
Exemplo n.º 25
0
    def __init__(self, app_id, signal):
        """
        :param int app_id: The ID of the application, between 0 and 255
        :param Signal signal: The signal to send
        :raise SpinnmanInvalidParameterException: If app_id is out of range
        """

        if app_id < 0 or app_id > 255:
            raise SpinnmanInvalidParameterException(
                "app_id", str(app_id), "Must be between 0 and 255")

        super().__init__(SDPHeader(
            flags=SDPFlag.REPLY_EXPECTED,
            destination_port=0,
            destination_cpu=0,
            destination_chip_x=self.DEFAULT_DEST_X_COORD,
            destination_chip_y=self.DEFAULT_DEST_Y_COORD),
                         SCPRequestHeader(command=SCPCommand.CMD_SIG),
                         argument_1=signal.signal_type.value,
                         argument_2=_get_data(app_id, signal),
                         argument_3=_ALL_CORE_MASK)
    def __init__(self, control_register, error_status, register_values):
        """
        :param control_register: The value of the control register
        :type control_register: int
        :param error_status: The value of the error_status
        :type error_status: int
        :param register_values: The values of the 16 router registers
        :type register_values: iterable of int
        :raise spinnman.exceptions.SpinnmanInvalidParameterException: If the\
                    number of register values is not 16
        """
        if len(register_values) != 16:
            raise SpinnmanInvalidParameterException(
                "len(register_values)",
                str(len(constants.ROUTER_REGISTER_REGISTERS)),
                "There must be exactly 16 register values")

        self._mon = (control_register >> 8) & 0x1F
        self._wait_1 = (control_register >> 16) & 0xFF
        self._wait_2 = (control_register >> 8) & 0xFF

        self._error_status = error_status

        self._register_values = register_values
Exemplo n.º 27
0
    def __init__(self, board_version=None, extra_boot_values=None):
        """ Builds the boot messages needed to boot the SpiNNaker machine

        :param int board_version: The version of the board to be booted
        :param extra_boot_values: Any additional values to be set during boot
        :type extra_boot_values: dict(SystemVariableDefinition, object)
        :raise SpinnmanInvalidParameterException:
            If the board version is not supported
        :raise SpinnmanIOException:
            If there is an error assembling the packets
        """
        if (board_version is not None
                and board_version not in spinnaker_boot_values):
            raise SpinnmanInvalidParameterException("board_version",
                                                    str(board_version),
                                                    "Unknown board version")

        # Get the boot packet values
        if board_version is not None:
            spinnaker_boot_value = spinnaker_boot_values[board_version]
        else:
            spinnaker_boot_value = SystemVariableBootValues()

        current_time = int(time.time())
        spinnaker_boot_value.set_value(SystemVariableDefinition.unix_timestamp,
                                       current_time)
        spinnaker_boot_value.set_value(SystemVariableDefinition.boot_signature,
                                       current_time)
        spinnaker_boot_value.set_value(SystemVariableDefinition.is_root_chip,
                                       1)

        # Set any additional values
        if extra_boot_values is not None:
            for variable, value in extra_boot_values.items():
                spinnaker_boot_value.set_value(variable, value)

        # Get the data as an array, to be used later
        spinnaker_boot_data = array.array("I", spinnaker_boot_value.bytestring)

        # Find the data file and size
        boot_data_file, boot_data_size = self._get_boot_image_file()

        # Compute how many packets to send
        n_words_to_read = boot_data_size // 4
        self._no_data_packets = int(
            math.ceil(float(boot_data_size) / _BOOT_MESSAGE_DATA_BYTES))

        # Read the data
        boot_data = array.array("I")
        with open(boot_data_file, "rb") as f:
            boot_data.fromfile(f, n_words_to_read)

        # Replace the appropriate part with the custom boot options
        offset = _BOOT_STRUCT_REPLACE_OFFSET
        length = _BOOT_STRUCT_REPLACE_LENGTH
        boot_data[offset:offset + length] = spinnaker_boot_data[0:length]

        # Byte swap and store the data for later use
        boot_data.byteswap()
        self._boot_data = boot_data.tobytes()
        self._n_bytes_to_read = n_words_to_read * 4
    def __init__(
            self, board_version, width, height, number_of_boards):
        """
        builds the boot messages needed to boot the spinnaker machine

        :param board_version: The version of the board to be booted
        :type board_version: int
        :param width: The width of the machine in chips
        :type width: int or None
        :param height: The height of the machine in chips
        :type height: int or None
        :param number_of_boards: the number of boards that this spinnaker
            machine is built up from
        :type number_of_boards: int
        :raise spinnman.exceptions.SpinnmanInvalidParameterException: If the\
                    board version is not supported
        :raise spinnman.exceptions.SpinnmanIOException: If there is an error\
                    assembling the packets
        """
        if board_version not in variable_boot_values.spinnaker_boot_values:
            raise SpinnmanInvalidParameterException(
                "board_version", str(board_version), "Unknown board version")

        # Get the boot packet values
        spinnaker_boot_value = \
            variable_boot_values.spinnaker_boot_values[board_version]

        current_time = int(time.time())
        spinnaker_boot_value.set_value(
            SystemVariableDefinition.unix_timestamp, current_time)
        spinnaker_boot_value.set_value(
            SystemVariableDefinition.boot_signature, current_time)
        spinnaker_boot_value.set_value(
            SystemVariableDefinition.is_root_chip, 1)
        spinnaker_boot_value.set_value(
            SystemVariableDefinition.x_size, int(width))
        spinnaker_boot_value.set_value(
            SystemVariableDefinition.y_size, int(height))

        # add any updates for multi-board systems
        for multi_board_n_boards, extra_variables in (
                variable_boot_values
                .spinnaker_multi_board_extra_configs.iteritems()):
            if number_of_boards >= multi_board_n_boards:
                for extra_variable, extra_value in extra_variables.iteritems():
                    spinnaker_boot_value.set_value(extra_variable, extra_value)

        # Get the data as an array, to be used later
        self._spinnaker_boot_data = array.array(
            "I", spinnaker_boot_value.bytestring)

        # Find the data file and size
        this_dir, _ = os.path.split(__file__)
        boot_data_file_name = os.path.join(
            this_dir, "boot_data", _BOOT_DATA_FILE_NAME)
        boot_data_file_size = os.stat(boot_data_file_name).st_size
        if boot_data_file_size > _BOOT_IMAGE_MAX_BYTES:
            raise SpinnmanIOException(
                "The boot file is too big at {} bytes ("
                "only files up to 32KB are acceptable".format(
                    boot_data_file_size))
        elif boot_data_file_size % 4 != 0:
            raise SpinnmanIOException(
                "The boot file size of {} bytes must"
                " be divisible by 4".format(boot_data_file_size))

        # Compute how many packets to send
        self._boot_data_file = open(boot_data_file_name, "rb")
        self._no_data_packets = int(math.ceil(
            float(boot_data_file_size) / float(_BOOT_MESSAGE_DATA_BYTES)))
        self._n_words_to_read = boot_data_file_size / 4