diff --git a/b_asic/architecture.py b/b_asic/architecture.py index cd318b29e1b92bc8b5fe6f2037bb5fdead2d42fd..510a29b4bcef6e1e10b3dd798e024f5b9dc60945 100644 --- a/b_asic/architecture.py +++ b/b_asic/architecture.py @@ -2,6 +2,7 @@ B-ASIC architecture classes. """ from collections import defaultdict +from io import TextIOWrapper from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple, Union, cast from graphviz import Digraph @@ -77,6 +78,37 @@ class HardwareBlock: def _digraph(self) -> Digraph: raise NotImplementedError() + @property + def schedule_time(self) -> int: + """The schedule time for hardware block""" + raise NotImplementedError() + + def write_component_declaration(self, f: TextIOWrapper, indent: int = 1) -> None: + """ + Write component declaration of hardware block. + + Parameters + ---------- + f : TextIOWrapper + File object (or other TextIOWrapper object) to write the declaration to. + indent : int, default: 1 + Indentation level to use for this process. + """ + raise NotImplementedError() + + def write_component_instantiation(self, f: TextIOWrapper, indent: int = 1) -> None: + """ + Write component instantiation of hardware block. + + Parameters + ---------- + f : TextIOWrapper + File object (or other TextIOWrapper object) to write the instantiation to. + indent : int, default: 1 + Indentation level to use for this process. + """ + raise NotImplementedError() + class Resource(HardwareBlock): """ @@ -135,6 +167,11 @@ class Resource(HardwareBlock): ret += f"|{{{'|'.join(outstrs)}}}" return "{" + ret + "}" + @property + def schedule_time(self) -> int: + # doc-string inherited + return self._collection.schedule_time + class ProcessingElement(Resource): """ @@ -277,11 +314,25 @@ of :class:`~b_asic.architecture.ProcessingElement` self._operation_inport_to_resource: Dict[InputPort, Resource] = {} self._operation_outport_to_resource: Dict[OutputPort, Resource] = {} + self._schedule_time = self._check_and_get_schedule_time() + # Validate input and output ports self.validate_ports() self._build_dicts() + def _check_and_get_schedule_time(self) -> int: + schedule_times = set() + for memory in self._memories: + schedule_times.add(memory.schedule_time) + for pe in self._processing_elements: + schedule_times.add(pe.schedule_time) + if self._direct_interconnects is not None: + schedule_times.add(self._direct_interconnects.schedule_time) + if len(schedule_times) != 1: + raise ValueError(f"Different schedule times: {schedule_times}") + return schedule_times.pop() + def _build_dicts(self): for pe in self.processing_elements: for operator in pe.processes: @@ -446,3 +497,8 @@ of :class:`~b_asic.architecture.ProcessingElement` @property def direct_interconnects(self) -> Optional[ProcessCollection]: return self._direct_interconnects + + @property + def schedule_time(self) -> int: + # doc-string inherited + return self._schedule_time diff --git a/b_asic/codegen/vhdl/architecture.py b/b_asic/codegen/vhdl/architecture.py index d59386df944d352491f48aa28af527692ad51ee4..eca28cdc4728a019dfa165e7521d8203bb16e9ca 100644 --- a/b_asic/codegen/vhdl/architecture.py +++ b/b_asic/codegen/vhdl/architecture.py @@ -26,14 +26,14 @@ def memory_based_storage( Parameters ---------- + f : TextIOWrapper + File object (or other TextIOWrapper object) to write the architecture onto. assignment : dict A possible cell assignment to use when generating the memory based storage. The cell assignment is a dictionary int to ProcessCollection where the integer corresponds to the cell to assign all MemoryVariables in corresponding process collection. If unset, each MemoryVariable will be assigned to a unique cell. - f : TextIOWrapper - File object (or other TextIOWrapper object) to write the architecture onto. word_length : int Word length of the memory variable objects. read_ports : int diff --git a/test/test_architecture.py b/test/test_architecture.py index 9830679c78240ea4f864bed9006cf3e3faa10079..8b52b0700e21097264185241d2d486200e6c4397 100644 --- a/test/test_architecture.py +++ b/test/test_architecture.py @@ -110,6 +110,7 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule): 'digraph {\n\tnode [shape=record]\n\tMEM0 [label="{{<in0> in0}|MEM0|{<out0>' ' out0}}"]\n}' ) + assert memory.schedule_time == 18 assert memory._digraph().source in (s, s + '\n') # Create architecture from @@ -117,9 +118,12 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule): processing_elements, memories, direct_interconnects=direct_conn ) + assert architecture.schedule_time == 18 + # assert architecture._digraph().source == "foo" for pe in processing_elements: print(pe) + assert pe.schedule_time == 18 for operation in pe._collection: operation = cast(OperatorProcess, operation) print(f' {operation}')