def build_machine(system_info,
                  core_resource=Cores,
                  sdram_resource=SDRAM,
                  sram_resource=SRAM):
    """Build a :py:class:`~rig.place_and_route.Machine` object from a
    :py:class:`~rig.machine_control.machine_controller.SystemInfo` object.

    .. note::
        Links are tested by sending a 'PEEK' command down the link which
        checks to see if the remote device responds correctly. If the link
        is dead, no response will be received and the link will be assumed
        dead. Since peripherals do not generally respond to 'PEEK'
        commands, working links attached to peripherals will also be marked
        as dead.

    .. note::
        The returned object does not report how much memory is free, nor
        how many cores are idle but rather the total number of working cores
        and the size of the heap. See :py:func:`.build_resource_constraints`
        for a function which can generate a set of
        :py:class:`~rig.place_and_route.constraints` which prevent the use of
        already in-use cores and memory.

    .. note::
        This method replaces the deprecated
        :py:meth:`rig.machine_control.MachineController.get_machine` method.
        Its functionality may be recreated using
        :py:meth:`rig.machine_control.MachineController.get_system_info` along
        with this function like so::

            >> sys_info = mc.get_system_info()
            >> machine = build_machine(sys_info)

    Parameters
    ----------
    system_info : :py:class:`rig.machine_control.machine_controller.SystemInfo`
        The resource availability information for a SpiNNaker machine,
        typically produced by
        :py:meth:`rig.machine_control.MachineController.get_system_info`.
    core_resource : resource (default: :py:class:`rig.place_and_route.Cores`)
        The resource type to use to represent the number of working cores on a
        chip, including the monitor, those already in use and all idle cores.
    sdram_resource : resource (default: :py:class:`rig.place_and_route.SDRAM`)
        The resource type to use to represent SDRAM on a chip. This resource
        will be set to the number of bytes in the largest free block in the
        SDRAM heap. This gives a conservative estimate of the amount of free
        SDRAM on the chip which will be an underestimate in the presence of
        memory fragmentation.
    sram_resource : resource (default: :py:class:`rig.place_and_route.SRAM`)
        The resource type to use to represent SRAM (a.k.a. system RAM) on a
        chip. This resource will be set to the number of bytes in the largest
        free block in the SRAM heap. This gives a conservative estimate of the
        amount of free SRAM on the chip which will be an underestimate in the
        presence of memory fragmentation.

    Returns
    -------
    :py:class:`rig.place_and_route.Machine`
        A :py:class:`~rig.place_and_route.Machine` object representing the
        resources available within a SpiNNaker machine in the form used by the
        place-and-route infrastructure.
    """
    try:
        max_cores = max(c.num_cores for c in itervalues(system_info))
    except ValueError:
        max_cores = 0

    try:
        max_sdram = max(c.largest_free_sdram_block
                        for c in itervalues(system_info))
    except ValueError:
        max_sdram = 0

    try:
        max_sram = max(c.largest_free_sram_block
                       for c in itervalues(system_info))
    except ValueError:
        max_sram = 0

    return Machine(width=system_info.width,
                   height=system_info.height,
                   chip_resources={
                       core_resource: max_cores,
                       sdram_resource: max_sdram,
                       sram_resource: max_sram,
                   },
                   chip_resource_exceptions={
                       chip: {
                           core_resource: info.num_cores,
                           sdram_resource: info.largest_free_sdram_block,
                           sram_resource: info.largest_free_sram_block,
                       }
                       for chip, info in iteritems(system_info)
                       if (info.num_cores != max_cores or
                           info.largest_free_sdram_block != max_sdram or
                           info.largest_free_sram_block != max_sram)
                   },
                   dead_chips=set(system_info.dead_chips()),
                   dead_links=set(system_info.dead_links()))