Exemple #1
0
 def __iter__(self):
     if self.module_class.is_switch_box:
         for x, y in product(range(-1, self.array.width), range(-1, self.array.height)):
             instance = self.array._sbox_grid[x][y]
             if isinstance(instance, AbstractInstance):
                 yield Position(x, y)
     else:
         for x, y in product(range(self.array.width), range(self.array.height)):
             instance = self.array._element_grid[x][y]
             if isinstance(instance, AbstractInstance):
                 yield Position(x, y)
Exemple #2
0
def _vpr_arch_array(xml, delegate, array, hierarchy=None):
    """Convert an array to 'single' elements.

    Args:
        xml (`XMLGenerator`):
        delegate (`FASMDelegate`):
        array (`Array`):
        hierarchy (:obj:`Sequence` [`AbstractInstance` ]):
    """
    position = hierarchical_position(
        hierarchy) if hierarchy is not None else Position(0, 0)
    for pos, instance in iteritems(array.element_instances):
        pos += position
        if instance.module_class.is_tile:
            fasm_prefix = '\n'.join(
                delegate.fasm_prefix_for_tile(
                    hierarchical_instance(instance, hierarchy)))
            attrs = {
                'type': instance.model.block.name,
                'priority': '1',
                'x': pos.x,
                'y': pos.y,
            }
            if fasm_prefix:
                with xml.element('single', attrs):
                    with xml.element('metadata'):
                        xml.element_leaf('meta', {'name': 'fasm_prefix'},
                                         fasm_prefix)
            else:
                xml.element_leaf('single', attrs)
        else:
            _vpr_arch_array(xml, delegate, instance.model,
                            hierarchical_instance(instance, hierarchy))
Exemple #3
0
    def instantiate_element(self, element, position):
        """Instantiate tile or array ``element`` and anchor its \(0, 0\) position to ``position`` in this array.

        Args:
            element (`AbstractArrayElement`):
            position (:obj:`tuple` [:obj:`int`, :obj:`int` ]):
        """
        position = Position(*position)
        # 1. check if the placement fits in the array or conflicts with any existing placements
        for x, y in product(range(-1, element.width), range(-1, element.height)):
            pos_in_elem = Position(x, y)
            pos_in_array = position + pos_in_elem
            for dim in iter(Dimension):
                if element.covers_channel(pos_in_elem, dim):
                    if (not self.covers_channel(pos_in_array, dim) or
                            (element.runs_channel(pos_in_elem, dim) and not self.runs_channel(pos_in_array, dim))):
                        raise PRGAInternalError("Array element '{}' does not fit in array '{}' at {} (channel {})"
                                .format(element, self, pos_in_array, dim.name))
            if element.covers_tile(pos_in_elem):
                if not self.covers_tile(pos_in_array):
                    raise PRGAInternalError("Array element '{}' does not fit in array '{}' at {} (tile)"
                            .format(element, self, position))
                elif self.get_root_element(pos_in_array) is not None:
                    raise PRGAInternalError("Conflicting tile at {} when instantiating array element '{}' at {}"
                            .format(pos_in_array, element, position))
            if element.covers_sbox(pos_in_elem):
                if not self.covers_sbox(pos_in_array):
                    raise PRGAInternalError("Array element '{}' does not fit in array '{}' at {} (switch box)"
                            .format(element, self, position))
                elif (self.sbox_instances.get(pos_in_array, None) is not None or
                        self.get_root_element_for_sbox(pos_in_array) is not None):
                    raise PRGAInternalError("Conflicting switch box at {} when instantiating array element '{}' at {}"
                            .format(pos_in_array, element, position))
        # 2. instantiate and add placeholders
        instance = ArrayElementInstance(self, element, position)
        self._element_grid[position.x][position.y] = instance
        for x, y in product(range(-1, element.width), range(-1, element.height)):
            pos_in_elem = Position(x, y)
            pos_in_array = position + pos_in_elem
            if element.covers_tile(pos_in_elem) and (x != 0 or y != 0):
                self._element_grid[pos_in_array.x][pos_in_array.y] = pos_in_elem
            if element.covers_sbox(pos_in_elem):
                self._sbox_grid[pos_in_array.x][pos_in_array.y] = pos_in_elem
        return instance
Exemple #4
0
    def create_global(self, global_, orientation=Orientation.auto, name=None):
        """Create and add a global input port to this block.

        Args:
            global_ (`Global`): The global wire this port is connected to
            orientation (`Orientation`): Orientation of this port
            name (:obj:`str`): Name of this port
        """
        orientation, _ = self._validate_orientation_and_position(
            orientation, Position(0, 0))
        port = IOBlockGlobalInputPort(self, global_, orientation, name)
        return self._add_port(port)
Exemple #5
0
def get_hierarchical_sbox(array, position, hierarchy=None):
    """Get the switch box at ``position`` down the hierarchy."""
    position = Position(*position)
    instance = array.get_root_element_for_sbox(position)
    if instance is None:
        return None
    elif instance.module_class.is_switch_box:
        return hierarchical_instance(instance, hierarchy, True)
    else:  # instance.module_class.is_array
        return get_hierarchical_sbox(
            instance.model, position - instance.position,
            hierarchical_instance(instance, hierarchy, True))
Exemple #6
0
    def create_output(self, name, width, orientation=Orientation.auto):
        """Create and add an output port to this block.

        Args:
            name (:obj:`str`): name of the created port
            width (:obj:`int`): width of the created port
            orientation (`Orientation`): orientation of this port
        """
        orientation, _ = self._validate_orientation_and_position(
            orientation, Position(0, 0))
        port = IOBlockOutputPort(self, name, width, orientation)
        return self._add_port(port)
Exemple #7
0
def populate_connection_box(box,
                            segments,
                            block,
                            orientation,
                            position=None,
                            channel=(0, 0)):
    """Populate connection box.

    Args:
        box (`ConnectionBox`):
        segments (:obj:`Sequence` [`Segment` ]):
        block (`BaseBlock`):
        orientation (`Orientation`):
        position (:obj:`tuple` [:obj:`int`, :obj:`int` ]): position of the ports in ``block`` that are connected by
            this cbox. This argument can be omitted if ``block`` is 1x1
        channel (:obj:`tuple` [:obj:`int`, :obj:`int` ]): position of the routing channel relative to this cbox
    """
    if orientation.dimension.perpendicular is not box.dimension:
        raise PRGAInternalError(
            "Connection box '{}' is {} and cannot be populated for '{}'".
            format(box, box.dimension.case("horizontal", "vertical"),
                   orientation))
    orientation, position = block._validate_orientation_and_position(
        orientation, position)
    channel = Position(*channel)
    # 1. segment bridges
    for sgmt, direction in product(iter(segments), iter(Direction)):
        # 1.1 output segment bridge
        box.get_or_create_node(
            SegmentBridgeID(channel, sgmt,
                            Orientation.compose(box.dimension, direction), 0,
                            SegmentBridgeType.cboxout))
        # 1.2 input segment bridge
        for section in range(sgmt.length):
            box.get_or_create_node(
                SegmentBridgeID(channel, sgmt,
                                Orientation.compose(box.dimension, direction),
                                section, SegmentBridgeType.cboxin))
    # 2. block port bridges
    # port position relative to cbox
    pos_port_rel_to_cbox = channel - orientation.case(
        north=(0, 0), east=(0, 0), south=(0, -1), west=(-1, 0))
    for port in itervalues(block.ports):
        if not (port.net_class.is_blockport and port.position == position
                and port.orientation in (orientation, Orientation.auto)):
            continue
        for subblock in range(block.capacity):
            box.get_or_create_node(
                BlockPortID(pos_port_rel_to_cbox, port, subblock))
Exemple #8
0
 def runs_channel(self, position, dimension):
     if not self.covers_channel(position, dimension):
         return False
     position = Position(*position)
     instance = self.get_root_element(position)
     if instance is not None and instance.model.covers_channel(position - instance.position, dimension):
         return instance.model.runs_channel(position - instance.position, dimension)
     instance = self.get_root_element(position + dimension.case((0, 1), (1, 0)))
     if instance is not None and instance.model.covers_channel(position - instance.position, dimension):
         return instance.model.runs_channel(position - instance.position, dimension)
     x, y = position
     if dimension.is_x:
         if x == 0 and not self.inner_coverage.west:
             return False
         elif x == self.width - 1 and not self.inner_coverage.east:
             return False
     else:
         if y == 0 and not self.inner_coverage.south:
             return False
         elif y == self.height - 1 and not self.inner_coverage.north:
             return False
     return True
Exemple #9
0
 def instantiate_sbox(self, box, position):
     """Instantiate switch box ``box``at ``position`` in this array.
     
     Args:
         box (`SwitchBox`):
         position (:obj:`tuple` [:obj:`int`, :obj:`int` ]):
     """
     position = Position(*position)
     # 1. check if the placement fits in the array or conflicts with any existing placements
     if not self.covers_sbox(position):
         raise PRGAInternalError("Switch box '{}' does not fit in array '{}' at {}"
                 .format(box, self, position))
     elif position in self.sbox_instances:
         raise PRGAInternalError("Conflicting switch box at {} when instantiating switch box '{}' in array {}"
                 .format(position, box, self))
     elif self.get_root_element_for_sbox(position) is not None:
         raise PRGAInternalError("Conflicting tile at {} when instantiating switch box '{}' in array {}"
                 .format(position, box, self))
     # 2. instantiate
     instance = SwitchBoxInstance(self, box, position)
     self._sbox_grid[position.x][position.y] = instance
     return instance
Exemple #10
0
    def create_direct_tunnel(self, name, source, sink, offset):
        """Create a direct inter-block tunnel.

        Args:
            name (:obj:`str`): Name of this direct inter-block tunnel
            source (`AbstractBlockPort`): Source of the tunnel
            sink (`AbstractBlockPort`): Sink of the tunnel
            offset (:obj:`tuple` [:obj:`int`, :obj:`int` ]): Position of the source block relative to the sink block.
                This definition is the opposite of how VPR defines a ``<direct>`` tag. In addition, ``offset`` is
                defined based on the position of the blocks, not the ports
        """
        if name in self._directs:
            raise PRGAAPIError(
                "Direct inter-block tunnel named '{}' is already created".
                format(name))
        elif not (source.parent.module_class.is_logic_block
                  and sink.parent.module_class.is_logic_block):
            raise PRGAAPIError(
                "Direct inter-block tunnel can only be created between logic block ports"
            )
        return self._directs.setdefault(
            name, DirectTunnel(name, source, sink, Position(*offset)))
Exemple #11
0
 def _validate_orientation_and_position(self, orientation, position):
     """Validate if the given ``orientation`` and ``position`` is on the edge of a block."""
     if position is None and not (self.width == 1 and self.height == 1):
         raise PRGAInternalError(
             "Argument 'position' is required because the size of block '{}' is {}x{}"
             .format(self, self.width, self.height))
     position = Position(*uno(position, (0, 0)))
     if position.x < 0 or position.x >= self.width or position.y < 0 or position.y >= self.height:
         raise PRGAInternalError("{} is not within block '{}'".format(
             position, self))
     elif orientation is Orientation.auto:
         if self.module_class.is_io_block:
             return orientation, position
         else:
             raise PRGAInternalError(
                 "'Orientation.auto' can only ued on IO blocks")
     elif orientation.case(north=position.y != self.height - 1,
                           east=position.x != self.width - 1,
                           south=position.y != 0,
                           west=position.x != 0):
         raise PRGAInternalError(
             "{} is not on the {} edge of block '{}'".format(
                 position, orientation.name, self))
     return orientation, position
Exemple #12
0
 def run(self, context):
     self.visited = set()
     self.__process_array(context, context.top, tuple(itervalues(context.segments)), Position(0, 0))
Exemple #13
0
 def __init__(self, parent, model, position):
     super(BaseRoutingInstance, self).__init__(parent, model)
     self._position = Position(*position)
Exemple #14
0
 def __init__(self, position, prototype, subblock=0):
     self.position = Position(*position)
     self.prototype = prototype
     self.subblock = subblock
Exemple #15
0
 def __init__(self, position, prototype, orientation, section=0):
     self.position = Position(*position)
     self.prototype = prototype
     self.orientation = orientation
     self.section = section
Exemple #16
0
 def position(self):
     """`Position`: Position of this port in the block."""
     return Position(0, 0)
Exemple #17
0
 def __init__(self, parent, name, width, orientation, position = (0, 0)):
     super(LogicBlockOutputPort, self).__init__(parent, name, width)
     self._orientation = orientation
     self._position = Position(*position)
Exemple #18
0
 def __init__(self, parent, global_, orientation, name = None, position = (0, 0)):
     super(LogicBlockGlobalInputPort, self).__init__(parent, global_, name)
     self._orientation = orientation
     self._position = Position(*position)
Exemple #19
0
def hierarchical_position(instance):
    """Calculate the position of ``instance`` in the top-level array."""
    return sum(iter(inst.position for inst in instance), Position(0, 0))
Exemple #20
0
def generate_fc(box,
                segments,
                block,
                orientation,
                fc,
                position=None,
                channel=(0, 0),
                create_nets_if_absent=True):
    """Add port-segment connections using FC values.

    Args:
        box (`ConnectionBox`):
        segments (:obj:`Sequence` [`Segment` ]):
        block (`BaseBlock`):
        orientation (`Orientation`):
        fc (`BlockFCValue`):
        position (:obj:`tuple` [:obj:`int`, :obj:`int` ]): position of the ports in ``block`` that are connected by
            this cbox. This argument can be omitted if ``block`` is 1x1
        channel (:obj:`tuple` [:obj:`int`, :obj:`int` ]): position of the routing channel relative to this cbox
        create_nets_if_absent (:obj:`bool`): If set, node ports are created if not found
    """
    if orientation.dimension.perpendicular is not box.dimension:
        raise PRGAInternalError(
            "Connection box '{}' is {} and cannot be populated for '{}'".
            format(box, box.dimension.case("horizontal", "vertical"),
                   orientation))
    orientation, position = block._validate_orientation_and_position(
        orientation, position)
    channel = Position(*channel)
    # port position relative to cbox
    pos_port_rel_to_cbox = channel - orientation.case(
        north=(0, 0), east=(0, 0), south=(0, -1), west=(-1, 0))
    # start generation
    iti = [0 for _ in segments]  # input-to-track index
    oti = [0 for _ in segments]  # output-to-track index
    for port in itervalues(block.ports):
        if not (port.net_class.is_blockport and port.position == position
                and port.orientation in (orientation, Orientation.auto)):
            continue
        for sgmt_idx, sgmt in enumerate(segments):
            nc = fc.port_fc(port, sgmt,
                            port.direction.is_input)  # number of connections
            if nc == 0:
                continue
            imax = port.direction.case(sgmt.length * sgmt.width, sgmt.width)
            istep = max(1, imax // nc)  # index step
            for _, port_idx, subblock in product(range(nc), range(port.width),
                                                 range(block.capacity)):
                # get the section and track id to be connected
                section = port.direction.case(iti[sgmt_idx] % sgmt.length, 0)
                track_idx = port.direction.case(iti[sgmt_idx] // sgmt.length,
                                                oti[sgmt_idx])
                for sgmt_dir in iter(Direction):
                    port_node = BlockPortID(pos_port_rel_to_cbox, port,
                                            subblock)
                    sgmt_node = SegmentBridgeID(
                        channel, sgmt,
                        Orientation.compose(box.dimension, sgmt_dir), section,
                        port.direction.case(SegmentBridgeType.cboxin,
                                            SegmentBridgeType.cboxout))
                    # get the bits
                    port_bus = box.get_or_create_node(
                        port_node) if create_nets_if_absent else box.ports.get(
                            port_node)
                    sgmt_bus = box.get_or_create_node(
                        sgmt_node) if create_nets_if_absent else box.ports.get(
                            sgmt_node)
                    if port_bus is None or sgmt_bus is None:
                        continue
                    if port.direction.is_input:
                        box.connect(sgmt_bus[track_idx], port_bus[port_idx])
                    else:
                        box.connect(port_bus[port_idx], sgmt_bus[track_idx])
                ni = port.direction.case(iti,
                                         oti)[sgmt_idx] + istep  # next index
                if istep > 1 and ni >= imax:
                    ni += 1
                port.direction.case(iti, oti)[sgmt_idx] = ni % imax