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)
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)
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)))
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)
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
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), )
def set_physical_position(self, ref_x: int, ref_y: int): self.user_phys_offset = WindowRef(ref_x, ref_y)
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
def get_last_ref() -> WindowRef: return WindowRef(WindowRef.columns - 1, WindowRef.rows - 1)
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)
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))