diff --git a/b_asic/architecture.py b/b_asic/architecture.py index 86d9ea48a07c4dd76460963f36ec013cf8025f23..d675dded72de660e28c2dd445229d6d00e50b2a9 100644 --- a/b_asic/architecture.py +++ b/b_asic/architecture.py @@ -45,7 +45,7 @@ class HardwareBlock: if entity_name is not None: self.set_entity_name(entity_name) - def set_entity_name(self, entity_name: str): + def set_entity_name(self, entity_name: str) -> None: """ Set entity name of hardware block. @@ -55,7 +55,7 @@ class HardwareBlock: The entity name. """ if not is_valid_vhdl_identifier(entity_name): - raise ValueError(f'{entity_name} is not a valid VHDL indentifier') + raise ValueError(f'{entity_name} is not a valid VHDL identifier') self._entity_name = entity_name def write_code(self, path: str) -> None: @@ -184,16 +184,41 @@ class Resource(HardwareBlock): # doc-string inherited return self._collection.schedule_time - def plot_content(self, ax: plt.Axes) -> None: + def plot_content(self, ax: plt.Axes, **kwargs) -> None: + """ + Plot the content of the resource. + + This plots the assigned processes executed on this resource. + + Parameters + ---------- + ax : Axes + Matplotlib Axes to plot in. + **kwargs + Passed to :meth:`b_asic.resources.ProcessCollection.plot` + """ if not self.is_assigned: - self._collection.plot(ax) + self._collection.plot(ax, **kwargs) else: for i, pc in enumerate(self._assignment): # type: ignore - pc.plot(ax=ax, row=i) + pc.plot(ax=ax, row=i, **kwargs) + + def show_content(self, title=None, **kwargs) -> None: + """ + Display the content of the resource. - def show_content(self): + This displays the assigned processes executed on this resource. + + Parameters + ---------- + title : str, optional + **kwargs + Passed to :meth:`b_asic.resources.ProcessCollection.plot` + """ fig, ax = plt.subplots() - self.plot_content(ax) + self.plot_content(ax, **kwargs) + if title: + fig.suptitle(title) fig.show() # type: ignore @property @@ -335,6 +360,27 @@ class Memory(Resource): self._collection.split_on_execution_time(heuristic=heuristic) ) + def assign(self, heuristic: str = "left_edge") -> None: + """ + Perform assignment of the memory variables. + + Parameters + ---------- + heuristic : str + The assignment algorithm. Depending on memory type the following are + available: + + * 'RAM' + * 'left_edge': Left-edge algorithm. + * 'graph_color': Graph-coloring based on exclusion graph. + * 'register' + * ... + """ + if self._memory_type == "RAM": + self._assign_ram(heuristic=heuristic) + else: # "register" + raise NotImplementedError() + class Architecture(HardwareBlock): """ @@ -393,7 +439,7 @@ of :class:`~b_asic.architecture.ProcessingElement` raise ValueError(f"Different schedule times: {schedule_times}") return schedule_times.pop() - def _build_dicts(self): + def _build_dicts(self) -> None: for pe in self.processing_elements: for operator in pe.processes: for input_port in operator.operation.inputs: @@ -419,7 +465,7 @@ of :class:`~b_asic.architecture.ProcessingElement` read_port.index, ) - def validate_ports(self): + def validate_ports(self) -> None: # Validate inputs and outputs of memory variables in all the memories in this # architecture memory_read_ports = set() @@ -455,7 +501,9 @@ of :class:`~b_asic.architecture.ProcessingElement` ) # Make sure all inputs and outputs in the architecture are in use - def get_interconnects_for_memory(self, mem: Memory): + def get_interconnects_for_memory( + self, mem: Memory + ) -> Tuple[Dict[Resource, int], Dict[Resource, int]]: """ Return a dictionary with interconnect information for a Memory. @@ -520,7 +568,6 @@ of :class:`~b_asic.architecture.ProcessingElement` def _digraph(self) -> Digraph: edges: Set[Tuple[str, str, str]] = set() dg = Digraph(node_attr={'shape': 'record'}) - # dg.attr(rankdir="LR") for i, mem in enumerate(self._memories): dg.node(mem.entity_name, mem._struct_def()) for i, pe in enumerate(self._processing_elements): @@ -536,8 +583,8 @@ of :class:`~b_asic.architecture.ProcessingElement` f"{cnt}", ) ) - for o, outp in enumerate(outputs): - for (dest, port), cnt in outp.items(): + for o, output in enumerate(outputs): + for (dest, port), cnt in output.items(): edges.add( ( f"{pe.entity_name}:out{o}", diff --git a/docs_sphinx/conf.py b/docs_sphinx/conf.py index f8148bc4a1b069a0368a746ed085dce0147a851f..7f335128f716a8eb2c9ad8ff62e68b698f909c50 100644 --- a/docs_sphinx/conf.py +++ b/docs_sphinx/conf.py @@ -8,7 +8,7 @@ import shutil -import qtgallery +# import qtgallery project = 'B-ASIC' copyright = '2020-2023, Oscar Gustafsson et al' @@ -28,7 +28,7 @@ extensions = [ 'sphinx_gallery.gen_gallery', 'numpydoc', # Needs to be loaded *after* autodoc. 'jupyter_sphinx', - 'qtgallery', + # 'qtgallery', ] templates_path = ['_templates'] @@ -71,11 +71,11 @@ sphinx_gallery_conf = { 'doc_module': ('b_asic',), 'reference_url': {'b_asic': None}, 'image_scrapers': ( - qtgallery.qtscraper, + # qtgallery.qtscraper, 'matplotlib', ), 'reset_modules': ( - qtgallery.reset_qapp, + # qtgallery.reset_qapp, 'matplotlib', ), } diff --git a/examples/secondorderdirectformiir_architecture.py b/examples/secondorderdirectformiir_architecture.py index f4e240a4d1241c225e346d5b02c0351a966a4a68..82b50d2f45155e762cfa434981ec51b389579f1f 100644 --- a/examples/secondorderdirectformiir_architecture.py +++ b/examples/secondorderdirectformiir_architecture.py @@ -42,7 +42,7 @@ schedule = Schedule(sfg, cyclic=True) schedule.show(title='Original schedule') # %% -# Rescheudle to only require one adder and one multiplier +# Reschedule to only require one adder and one multiplier schedule.move_operation('add4', 2) schedule.move_operation('cmul5', -4) schedule.move_operation('cmul4', -5) @@ -68,18 +68,22 @@ p_in = ProcessingElement(inputs, entity_name='input') p_out = ProcessingElement(outputs, entity_name='output') # %% -# Extract memory variables +# Extract and assign memory variables mem_vars = schedule.get_memory_variables() mem_vars.show(title="All memory variables") direct, mem_vars = mem_vars.split_on_length() -direct.show(title="Direct interconnects") mem_vars.show(title="Non-zero time memory variables") mem_vars_set = mem_vars.split_on_ports(read_ports=1, write_ports=1, total_ports=2) -memories = set() +memories = [] for i, mem in enumerate(mem_vars_set): - memories.add(Memory(mem, entity_name=f"memory{i}")) - mem.show(title=f"memory{i}") + memory = Memory(mem, memory_type="RAM", entity_name=f"memory{i}") + memories.append(memory) + mem.show(title=f"{memory.entity_name}") + memory.assign("left_edge") + memory.show_content(title=f"Assigned {memory.entity_name}") + +direct.show(title="Direct interconnects") # %% # Create architecture