예제 #1
0
 def __init__(self, columns: int, rows: int, chain: AsProcessingChain):
     self.window_modules = []
     self.layers = []
     self.chain = chain
     self.columns = columns
     self.rows = rows
     self.min_bits_per_section = 64
     self.user_connections = []
     self.pipeline_traversal = []
     WindowRef.set_windowsize(self.columns, self.rows)
예제 #2
0
    def __init_sections__(self):
        """Splits up the sections to align with all overlaps.
        Run only once right after initializing the sections,
        as it expects a single section per layer!"""
        for layer in self.layers:
            to_split = []
            # Instantiate a new section over the entire layer
            sec = AsWindowSection(layer, layer.data_width)
            sec.set_bounds(layer.start_ref, layer.end_ref)
            # and add it to the layer
            layer.sections.append(sec)

            # The section starts at the pixel/data input
            # (no need to build a pipeline without data to process)
            sec.start_ref.update(sec.parent.input.refnum)
            layer.start_ref = sec.start_ref

            # Sort the filter outputs by their refnums
            outputs = sec.parent.output_refs
            outputs.sort(key=lambda ref: ref.refnum)

            # Determine positions where the section must be buffered in FFs
            # This is at positions where a filter output appears after
            # a data point without an output:
            # IN -> ff -> ff -> |SPLIT| out -> out -> ff -> |SPLIT| out -> ...
            for idx in range(len(outputs)):
                outref = outputs[idx]
                # Don't split right at the input
                if idx == 0:
                    # First output requires special attention, as there's no
                    # previous output to reference
                    if outref.refnum != sec.start_ref.refnum:
                        to_split.append(
                            WindowRef.get_ref_from_refnum(outref.refnum))
                    continue
                # If an output appears right after another ouput, no split!
                if abs(outref.refnum - outputs[idx - 1].refnum) == 1:
                    continue
                else:  # otherwise:
                    to_split.append(
                        WindowRef.get_ref_from_refnum(outref.refnum))
                    continue
            # Last output is the last datapoint of the section/pipeline
            sec.end_ref.update(outputs[-1].refnum)
            layer.end_ref = sec.end_ref

            # Split the section of this layer into subsections
            # Each subsection is a candidate that may be stored in BRAM
            for ref in to_split:
                # The split method returns the section further along the
                # buffer (higher refnum), which may be split again
                sec = sec.split(ref)
예제 #3
0
    def __connect_layer_input__(self, inter: Interface, layer: AsLayer,
                                anchor: WindowRef):
        window = isinstance(inter, AsWindowInterface)

        if window:
            if len(inter.references) > 1:
                LOG.error(
                    ("Tried connection interface '%s' input to layer '%s'"
                     " with more than one port!"),
                    inter.name,
                    layer.name,
                )
                raise AsConnectionError(
                    ("Layer input interfaces must have only"
                     " one port!"))
            else:
                # There should only be one port / reference for layer input interfaces
                port = inter.references[0].port
        elif isinstance(inter, Interface):
            try:  # Assuming AsStream interface!
                port = inter.get_port("data")
            except NameError as err:
                LOG.error("Could not find port 'data' in '%s'! - '%s'",
                          inter.name, str(err))
                raise AsConnectionError(
                    ("When connecting '{}' in 2D Window "
                     "Pipeline to '{}'. Missing port 'data'! Might not be "
                     "AsStream!").format(inter.name, layer.name))
        if anchor is None:
            anchor = WindowRef(0, 0)
        module = inter.parent
        # The input of each layer should be @ (0,0)
        # The pixel offset between the base layer and all other layers
        # is determined by each layers 'offset' attribute
        layer.set_input(AsConnectionRef(WindowRef(0, 0), port))
        layer.set_offset(WindowRef(0, 0))

        # Register the layer input connection with the layer, interface
        # and module objects involved
        layer.interfaces.append(inter)
        layer.modules.append(module)
        # Assuming window interface is only present in AsWindowModule
        if window:
            module.output_layers.append(layer)
            inter.layer = layer
        elif isinstance(module, AsModule):
            inter.outgoing.append(layer)
        else:
            LOG.error("Connected to unkown object type!")
            raise TypeError("Unkown module type for connection: {}".format(
                type(module)))
예제 #4
0
 def __init__(self):
     super().__init__()
     self.input_refs = []  # Updated. AsLayerRef objects
     self.output_refs = []  # Updated. AsLayerRef objects
     self.delay = None  # Module output delay in clock cycles
     self.window_interfaces = []  # List of AsWindowInterface objects
     self.input_layers = []  # List of AsLayers this module gets data from
     self.output_layers = []  # List of AsLayers with this module as input
     # ↓ Offset that applies to all outgoing references
     self.offset = WindowRef(0, 0)
     self.user_phys_offset = None  # Physical position set by user
     self.pipe = None  # Reference to the As2DWindowPipeline object (parent)
예제 #5
0
 def add_layer(self,
               name: str,
               data_width: int,
               baselayer: bool = False) -> AsLayer:
     """Add a new layer to the data pipeline.
     The first layer that is added is the 'base layer'.
     All layers must be added to the pipe before running the section tools!
     Parameters:
         name: Name of the layer. Must be unique.
         data_width: Data width in bits for this layer.
     Returns the layer object."""
     # Check if a layer of the provided name already exists.
     if name in [l.name for l in self.layers]:
         raise AttributeError(
             "Layer with name {} already exists!".format(name))
     layer = AsLayer(name, data_width, self)
     # If this is the first layer to be added, set it as the base layer
     if not self.layers or baselayer:
         layer.base_layer = True
     # Set the initial section references to span the entire layer.
     layer.set_bounds(WindowRef(0, 0),
                      WindowRef(col=self.columns - 1, row=self.rows - 1))
     self.layers.append(layer)
     return layer
예제 #6
0
 def connect(self,
             interface: Interface,
             layer: AsLayer,
             offset: tuple = None):
     """Connect an interface from an AsModule to a pipeline data layer."""
     if offset:
         anchor = WindowRef(*offset)
     else:
         anchor = None
     if interface.direction == "out":
         con_type = self.LAYER_INPUT
     else:
         con_type = self.LAYER_OUTPUT
     conjob = self.UserConJob(con_type, interface, layer, anchor)
     self.user_connections.append(conjob)
     LOG.debug(
         "Pipe: Got connection job for '%s' and layer '%s' @ %s.",
         repr(interface),
         str(layer),
         "auto" if not anchor else str(anchor),
     )
예제 #7
0
 def set_physical_position(self, ref_x: int, ref_y: int):
     self.user_phys_offset = WindowRef(ref_x, ref_y)
예제 #8
0
    def update_footprint(self) -> bool:
        """Update and set the footprint size for this interface based on the
        auto-tags of it's ports.
        Also attempts to parse the variable size of the 'generic_window'
        datatype.
        Returns whether the generic_window data type could be parsed."""
        parse_successful = True
        left_col = 0
        right_col = 0
        upper_row = 0
        lower_row = 0
        for port in self.ports:
            if getattr(port, "window_config", None) is None:
                continue  # Skip non-window ports

            if not port.generics:
                # Find and assign generics to the port
                gen_names = extract_generics(port.data_width)
                for name in gen_names:
                    gen = self.parent.get_generic(name, suppress_error=True)
                    if gen:
                        port.add_generic(gen)

            if PIPE_WINDOW_TYPE in port.data_type:
                if not isinstance(port.data_width, str):
                    continue
                widths = parse_gwindow_type(port.data_width, port.generics)
                if len(widths) < 3:
                    LOG.error(
                        "Syntax error detected! In '%s' for port '%s'",
                        self.name,
                        port.code_name,
                    )

                # Add the auto-tag information to the window size
                window = data_widths_to_window(widths[0], widths[1])

                # Determine footprint of this window-port
                if window is not None:
                    # Add actual data width
                    port.data_width = widths[2]

                    col_offset = int(port.window_config.x)
                    row_offset = int(port.window_config.y)
                    window.from_x += col_offset
                    window.to_x += col_offset
                    window.from_y += row_offset
                    window.to_y += row_offset

                    # Add window-refs for each "pixel"
                    for x in range(window.from_x, window.to_x + 1):
                        for y in range(window.from_y, window.to_y + 1):
                            self.add_window_ref(
                                AsConnectionRef(WindowRef(col=x, row=y), port))
                else:
                    LOG.info(
                        ("Could not determine window size for "
                         "interface '%s' of module '%s'! Unresolved "
                         "generics present in '%s'!"),
                        self.name,
                        self.parent.name,
                        str(port.data_width),
                    )
                    parse_successful = False
            else:  # Not a window type:
                pref = WindowRef(int(port.window_config.x),
                                 int(port.window_config.y))
                self.add_window_ref(AsConnectionRef(pref, port))

        for ref in self.references:
            if ref.col < left_col:
                left_col = ref.col
            elif ref.col > right_col:
                right_col = ref.col
            if ref.row < upper_row:
                upper_row = ref.row
            elif ref.row > lower_row:
                lower_row = ref.row

        self.footprint = WindowDef(left_col, right_col, upper_row, lower_row)
        self.sort_references()
        return parse_successful
예제 #9
0
 def get_last_ref() -> WindowRef:
     return WindowRef(WindowRef.columns - 1, WindowRef.rows - 1)
예제 #10
0
    def __connect_layer_output__(self, inter: Interface, layer: AsLayer,
                                 anchor: WindowRef):
        # TODO: Handle anchor case
        window = isinstance(inter, AsWindowInterface)

        # Check if the interface is ready to be connected
        if window:
            if not inter.update_footprint():
                LOG.error(
                    ("Could not connect interface '%s'! The generics used in "
                     "'%s' need to be defined before making the connection!"),
                    inter.name,
                    inter.data_type,
                )
                raise ValueError(
                    "Undefined generics in interface '{}': '{}'".format(
                        inter.name, inter.data_type))
        if not anchor:
            anchor = WindowRef(0, 0)
        if layer.input is None:  # Just making sure!
            LOG.error(
                ("Attempted to connect output interface '%s' to layer"
                 " '%s' without an input!"),
                inter.name,
                layer.name,
            )
            raise AsConnectionError(("Cannot connect outputs to layer "
                                     "without an input!"))

        module = inter.parent

        if window:
            if module.user_phys_offset:
                module.offset = module.user_phys_offset
            else:
                module.offset = anchor
            # For each input port of the interface
            for pref in inter.references:
                layer_ref = layer.add_output(pref)
                # Add the resulting reference to the module
                module.input_refs.append(layer_ref)
                # TODO: Testing!
        else:
            try:
                port = inter.get_port("data", suppress_error=True)
            except NameError as err:
                LOG.error("Could not find port 'data' in '%s'! - '%s'",
                          inter.name, str(err))
                raise AsConnectionError(
                    ("When connecting '{}' in 2D Window "
                     "Pipeline to '{}'. Missing port 'data'! Might not be "
                     "AsStream!").format(inter.name, layer.name))
            pref = AsConnectionRef(WindowRef(0, 0), port)
            layer.add_output(pref, True)

        # Register this connection with the module, layer and interface involved
        layer.interfaces.append(inter)
        layer.modules.append(module)
        if window:
            module.input_layers.append(layer)
            inter.layer = layer
        elif isinstance(module, AsModule):
            inter.incoming.append(layer)
예제 #11
0
            LOG.error("Wrong data type passed to pipeline.connect()!")
            raise TypeError("Cannot connect data layer with object of type {}!"
                            .format(type(inter)))

        # TODO: Establish connection
"""

# ↑↑↑ OLD CODE ↑↑↑ !for reference only!

# DEBUG for WindowSection management:
if __name__ == "__main__":
    LOG = as_log.init_log(loglevel_console="DEBUG")
    pipe = As2DWindowPipeline(640, 480, None)

    l0 = pipe.add_layer("grey", 8)
    l0.set_input(WindowRef(col=0, row=0))
    # l0.add_outputs(window=WindowDef(0,2,0,2))

    l1 = pipe.add_layer("gauss", 8)
    l1.set_input(WindowRef(1, 0))
    l1.add_output(WindowRef(6, 1))

    l2 = pipe.add_layer("cordic", 12)
    l2.set_input(WindowRef(7, 1))
    l2.add_output(WindowRef(5, 5))
    l2.add_output(WindowRef(6, 5))

    l3 = pipe.add_layer("result", 8)
    l3.set_input(WindowRef(15, 3))
    l3.add_output(WindowRef(6, 4))
    # l3.add_outputs(window=WindowDef(7, 9, 4, 6))