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)
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))
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
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)
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))
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)
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))
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
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
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)))
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
def run(self, context): self.visited = set() self.__process_array(context, context.top, tuple(itervalues(context.segments)), Position(0, 0))
def __init__(self, parent, model, position): super(BaseRoutingInstance, self).__init__(parent, model) self._position = Position(*position)
def __init__(self, position, prototype, subblock=0): self.position = Position(*position) self.prototype = prototype self.subblock = subblock
def __init__(self, position, prototype, orientation, section=0): self.position = Position(*position) self.prototype = prototype self.orientation = orientation self.section = section
def position(self): """`Position`: Position of this port in the block.""" return Position(0, 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)
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)
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))
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